Compare commits

..

1584 Commits

Author SHA1 Message Date
Péter Szilágyi
b8b9f7f447 params: release Geth 1.8.2 stable 2018-03-05 15:48:48 +02:00
Anton Evangelatov
c636ac4045 github: config for probot-stale bot (#16235)
* github: config for probot-stale bot

* github: use stale label, instead of wontfix
2018-03-05 15:23:26 +02:00
Péter Szilágyi
bd6879ac51 core/vm, crypto/bn256: switch over to cloudflare library (#16203)
* core/vm, crypto/bn256: switch over to cloudflare library

* crypto/bn256: unmarshal constraint + start pure go impl

* crypto/bn256: combo cloudflare and google lib

* travis: drop 386 test job
2018-03-05 14:33:45 +02:00
Péter Szilágyi
223fe3f26e Merge pull request #16229 from karalabe/evm-call-fix
cmd/evm, core/vm, internal/ethapi: don't disable call gas metering
2018-03-05 14:23:48 +02:00
Péter Szilágyi
b7e57ca1d0 cmd/evm, core/vm, internal/ethapi: don't disable call gas metering 2018-03-05 14:01:13 +02:00
Martin Holst Swende
478143d69a utils: fix #16138 by checking if vhosts flag is set (#16141)
* utils: fix #16138 by checking if vhosts flag is set

* utils,node: fix defaults for rpcvhosts

* node,utils: address review concerns
2018-03-05 13:02:32 +02:00
Guillaume Ballet
abed63c38f Merge pull request #16250 from gluk256/317-fatalf
whisper: refactoring go-routines workflow

Move the call mailServer.Init() down (to the bottom of the function) because if the function initialize() completes successfully, then it will be followed by mailServer.Close() in shutdown(). The workflow of the corresponding goroutines is clearer now.
2018-03-05 10:49:25 +01:00
Kyuntae Ethan Kim
d429a92f09 consensus/ethash: fixed typo (#16253) 2018-03-05 11:32:56 +02:00
Vlad
61a061c9b4 whisper: refactoring go-routines 2018-03-04 23:35:05 +01:00
protolambda
0b814d32f8 accounts/abi: Abi binding support for nested arrays, fixes #15648, including nested array unpack fix (#15676)
* accounts/abi/bind: support for multi-dim arrays

Also:
- reduce usage of regexes a bit.
- fix minor Java syntax problems

Fixes #15648

* accounts/abi/bind: Add some more documentation

* accounts/abi/bind: Improve code readability

* accounts/abi: bugfix for unpacking nested arrays

The code previously assumed the arrays/slices were always 1 level
deep. While the packing supports nested arrays (!!!).

The current code for unpacking doesn't return the "consumed" length, so
this fix had to work around that by calculating it (i.e. packing and
 getting resulting length) after the unpacking of the array element.
It's far from ideal, but unpacking behaviour is fixed now.

* accounts/abi: Fix unpacking of nested arrays

Removed the temporary workaround of packing to calculate size, which was
incorrect for slice-like types anyway.
Full size of nested arrays is used now.

* accounts/abi: deeply nested array unpack test

Test unpacking of an array nested more than one level.

* accounts/abi: Add deeply nested array pack test

Same as the deep nested array unpack test, but the other way around.

* accounts/abi/bind: deeply nested arrays bind test

Test the usage of bindings that were generated
for methods with multi-dimensional (and not
just a single extra dimension, like foo[2][3])
array arguments and returns.

edit: trigger rebuild, CI failed to fetch linter module.

* accounts/abi/bind: improve array binding

wrapArray uses a regex now, and arrayBindingJava is improved.

* accounts/abi: Improve naming of element size func

The full step size for unpacking an array
 is now retrieved with "getFullElemSize".

* accounts/abi: support nested nested array args

Previously, the code only considered the outer-size of the array,
ignoring the size of the contents. This was fine for most types,
but nested arrays are packed directly into it, and count towards
the total size. This resulted in arguments following a nested
array to replicate some of the binary contents of the array.

The fix: for arrays, calculate their complete contents size:
 count the arg.Type.Elem.Size when Elem is an Array, and
 repeat when their child is an array too, etc.
The count is the number of 32 byte elements, similar to how it
 previously counted, but nested.

* accounts/abi: Test deep nested arr multi-arguments

Arguments with a deeply nested array should not cause the next arguments
to be read from the wrong position.
2018-03-04 23:24:17 +01:00
Guillaume Ballet
7b1d637098 Merge pull request #16245 from gluk256/311-close-channel
whisper: close the `done` channel in one location
2018-03-04 23:22:26 +01:00
Vlad
95cca85d6d whisper: minor refactoring 2018-03-03 21:37:16 +01:00
gluk256
66cd41af1e Merge pull request #16231 from gluk256/303-reader
whisper: filereader mode introduced to wnode
2018-03-03 09:40:01 +01:00
gluk256
fa375955ad whisper/whisperv6: delete unused function (#16234) 2018-03-03 00:54:15 +01:00
Felföldi Zsolt
5ad7b9123c light: new CHTs (#16233) 2018-03-03 00:52:54 +01:00
Péter Szilágyi
ca64a122d3 eth/downloader: save and load trie sync progress (#16224) 2018-03-03 00:52:39 +01:00
Felix Lange
12f4d28411 internal/debug: add support for mutex profiles (#16230) 2018-03-03 00:52:21 +01:00
Vlad
6219a33822 whisper: filereader mode introduced to wnode 2018-03-02 14:54:54 +01:00
Péter Szilágyi
49bcb5fbd5 Merge pull request #16228 from karalabe/faucet-background-skip
cmd/faucet: update state in background, skip when busy
2018-03-02 12:13:19 +02:00
Péter Szilágyi
6f13e515f4 cmd/faucet: update state in background, skip when busy 2018-03-02 12:02:23 +02:00
Zhenguo Niu
d520bf4503 cmd/swarm: fix some typos in manifest cmd (#16227)
Replace "atleast" with "at least" in the manifest error message.
2018-03-02 10:59:26 +01:00
Guillaume Ballet
a76e46e3d7 Merge pull request #16223 from gluk256/300-msg-serialiation
whisper: topics replaced by bloom filters in mailserver communication
2018-03-01 20:27:20 +01:00
Anton Evangelatov
3ca3fffdf0 metrics: fix flaky Example metrics test (#16222)
* metrics: add sleep to test in order to get predictable output

* metrics: relax constraints on timer test
2018-03-01 19:55:31 +02:00
Vlad
ee75a90ab4 whisper: topics replaced by bloom filters 2018-03-01 16:04:09 +01:00
gluk256
5a150e1b77 whisper: serious security issue fixed (#16219)
The diagnostic tool was saving the unencrypted version of the messages, which is an obvious
security flaw. As of this commit:
  * encrypted messages saved instead of plain text.
  * all messages are stored, even that created by the user of wnode.
2018-03-01 09:34:46 +01:00
Guillaume Ballet
9b4e182ce5 Merge pull request #16210 from gluk256/288-filter-optimization
whisper: message filtering optimization

Only run the message through filters who registered their interest.
2018-02-28 17:28:09 +01:00
Vlad
d24d10a764 whisper: style fixes 2018-02-28 15:05:35 +01:00
Guillaume Ballet
52bb0a1ec7 Merge pull request #16214 from b00ris/whisperv6_datarace
whisper: fixed dataraces in peer unit tests
2018-02-28 14:31:19 +01:00
Guillaume Ballet
1843615456 Merge pull request #16206 from gluk256/277-mailserver
whisper: mailserver no longer supports the signature validation

Mailserver is provided as an example, but client validation belongs to the upper layer protocol and
needs not be covered in this example. The check that was previously available hinders the switch
to libp2p so we agreed not to include that check in that example code anymore.
2018-02-28 14:10:08 +01:00
Péter Szilágyi
7843192c8e Merge pull request #16217 from karalabe/rpc-receipt-fetch-fix
internal/ethapi: fix getTransactionReceipt
2018-02-28 13:40:17 +02:00
b00ris
62c239f608 whisper: fix typo 2018-02-28 14:38:42 +03:00
Péter Szilágyi
8f43c97433 Merge pull request #16207 from karalabe/drop-go1.7
travis, build, consensus: drop support for Go 1.7
2018-02-28 13:29:58 +02:00
Péter Szilágyi
ba7b384019 internal/ethapi: fix getTransactionReceipt 2018-02-28 12:40:15 +02:00
Mark Rushakoff
98ec5e5011 core/asm: rename isAlphaNumeric to isLetter (#16212)
The function would return false for numbers, so isLetter is a more
accurate description of the behavior.
2018-02-28 12:20:07 +02:00
b00ris
cf52d5c91f whisper: fixed datarace 2018-02-28 09:50:36 +03:00
Vlad
a69cb3b4ff whisper: comment updated 2018-02-28 00:39:38 +01:00
Vlad
c733792be4 whsiper: refactoring 2018-02-27 23:38:20 +01:00
Vlad
014d8d9837 whisper: message filtering optimized 2018-02-27 21:16:15 +01:00
Péter Szilágyi
17b0e226d3 travis, build, consensus: drop support for Go 1.7 2018-02-27 18:25:56 +02:00
Vlad
5e30a5f66e whisper: test fixed 2018-02-27 15:52:10 +01:00
Vlad
dadf4d53ab whisper: mailserver no longer supports the signature vaidation 2018-02-27 15:45:00 +01:00
Elad Nachmias
b574b57766 swarm: give correct error on 0x hash prefix (#16195)
- added a case error struct that contains information about certain error cases
in which we would like to output more information to the client
- added a validation method that iterates and adds the information that is
stored in the error cases
2018-02-27 15:32:38 +02:00
Anton Evangelatov
18bb3da55e node: fill StandardCounters as part of debugapi/metrics (#16054) 2018-02-27 15:30:07 +02:00
Elad Nachmias
dd389e595f eth: added travis build badge (#16117)
* eth: added travis build status for master branch

* README: fix travis badge order, link to CI
2018-02-27 13:04:47 +02:00
Saulius Grigaitis
c41f1a3e23 puppeth: fix Parity Chain Spec parameter GasLimitBoundDivision (#16188) 2018-02-27 12:56:51 +02:00
Andrey Petrov
2e9c8fd4fb eth, les: allow exceeding maxPeers for trusted peers (#16189)
Fixes #3326, #14472
2018-02-27 12:52:59 +02:00
Guillaume Ballet
4c845bdc27 Merge pull request #16198 from gluk256/266-wnode
whisper: refactor wnode to systematically store messages if a directory is provided
2018-02-26 21:23:51 +01:00
Vlad
f4e676cccd whipser: comments updated 2018-02-26 19:26:36 +01:00
JU HYEONG PARK
61c9730b2d p2p: fix doEncHandshake documentation (#16184) 2018-02-26 17:22:46 +01:00
Vlad
6e0667fa06 whisper: wnode updated - all messages are saved if savedir param is given 2018-02-26 13:58:04 +01:00
Martin Holst Swende
f83237573f core: make current*Block atomic, and accessor functions mutex-free (#16171)
* core: make current*Block atomic, and accessor functions mutex-free

* core: fix review concerns

* core: fix error in atomic assignment

* core/light: implement atomic getter/setter for headerchain
2018-02-26 11:53:10 +02:00
Domino Valdano
d398d04e27 cmd/geth: fix broken links to JavaScript-Console wiki in cmd line help (#16183)
* Fixed broken link to JavaScript-Console wiki in cmd line help

* cmd/geth: Added missing r in 'JavaScript'
2018-02-26 11:38:17 +02:00
Anton Evangelatov
764878d988 contracts/chequebook: increase interval between auto deposits (#16178) 2018-02-26 11:36:26 +02:00
cooganb
22fc6928d7 swarm: creates Swarm landing page for browser 'localhost:xxxx/' GET request when running Swarm (#15926)
* swarm: began work on GetHandleFile method re: issue #155

* swarm: now able to serve landing page template

* swarm: added landing page template

* swarm: landing page has working input

* swarm: fixed CSS issue in template

* swarm: deleted extra lines

* swarm: deleted time header and made redirect a relative path

* swarm: removed code mistakenly left
2018-02-26 09:56:40 +01:00
Guillaume Ballet
423c8bb1d8 Merge pull request #16176 from gluk256/255-refactoring
whisper: filters no longer get removed after a while
2018-02-23 18:02:51 +01:00
Anton Evangelatov
114738982e swarm/metrics: introduce metrics export flag (#16177) 2018-02-23 16:22:16 +01:00
Vlad
6919c36432 whisper: refactoring 2018-02-23 14:52:25 +01:00
Anton Evangelatov
dcca613a0b swarm: initial instrumentation (#15969)
* swarm: initial instrumentation with go-metrics

* swarm: initialise metrics collection and add ResettingTimer to HTTP requests

* swarm: update metrics flags names. remove redundant Timer.

* swarm: rename method for periodically updating gauges

* swarm: finalise metrics after feedback

* swarm/network: always init kad metrics containers

* swarm/network: off-by-one index in metrics containers

* swarm, metrics: resolved conflicts
2018-02-23 14:19:59 +01:00
Lewis Marshall
b677a07d36 swarm/api/http: Fix using deprecated bzzr scheme (#16152)
Without this, deprecated bzzr requests just return an empty response.

Signed-off-by: Lewis Marshall <lewis@lmars.net>
2018-02-23 14:09:01 +01:00
gluk256
4702ace5f7 Merge pull request #16172 from gluk256/244-light-client
whisper: light client mode introduced
2018-02-23 14:07:29 +01:00
Péter Szilágyi
89f914c030 core: flush out trie cache more meaningfully on stop (#16143)
* core: flush out trie cache more meaningfully on stop

* core: upgrade legacy tests to chain maker
2018-02-23 14:02:33 +02:00
Guillaume Ballet
fb5d085234 Merge pull request #16146 from status-im/pombeirp/whisperv6-peer-race-cond-fix
Fix race condition in whisperv6/peer.go
2018-02-23 11:49:47 +01:00
Martin Holst Swende
44d40ffce1 core, vm, common: define constantinople fork + shift (#16045)
* core, vm, common: define constantinople fork, start implementation of shift instructions

* vm: more testcases

* vm: add tests for intpool erroneous intpool handling

* core, vm, common: fix constantinople review concerns

* vm: add string<->op definitions for new opcodes
2018-02-23 12:32:57 +02:00
Vlad
d7b4b40cb6 whisper: light client mode introduced 2018-02-23 11:10:28 +01:00
Anton Evangelatov
ae9f97221a metrics: pull library and introduce ResettingTimer and InfluxDB reporter (#15910)
* go-metrics: fork library and introduce ResettingTimer and InfluxDB reporter.

* vendor: change nonsense/go-metrics to ethersphere/go-metrics

* go-metrics: add tests. move ResettingTimer logic from reporter to type.

* all, metrics: pull in metrics package in go-ethereum

* metrics/test: make sure metrics are enabled for tests

* metrics: apply gosimple rules

* metrics/exp, internal/debug: init expvar endpoint when starting pprof server

* internal/debug: tiny comment formatting fix
2018-02-23 11:56:08 +02:00
Péter Szilágyi
7f74bdf8dd Merge pull request #16164 from karalabe/les-receipt-fix-optimal
eth, les, light: filter on logs only, derive receipts on demand
2018-02-23 11:50:16 +02:00
Balint Gabor
a1984ce727 Merge pull request #15748 from janos/multiple-ens-endpoints
swarm: repeated --ens-api CLI flag (#14386)
2018-02-22 23:15:13 +01:00
Janos Guljas
6a9730edaa swarm, cmd/swarm: Merge branch 'master' into multiple-ens-endpoints 2018-02-22 18:51:34 +01:00
Ivan Daniluk
8522b31221 p2p: remove unused code (#16158)
* p2p: remove unused code

* p2p: remove unused imports
2018-02-22 19:20:28 +02:00
Péter Szilágyi
5cf1d35470 eth, les, light: filter on logs only, derive receipts on demand 2018-02-22 19:12:43 +02:00
Janoš Guljaš
4535247793 rpc: set rpcRequest.service as methodNotFoundError.service value (#16163)
RPC Server readRequest method sets the serverRequest error service
value as the rpcRequest.method and this change sets it to the right
service value.
2018-02-22 18:39:28 +02:00
Péter Szilágyi
44c393607e Merge pull request #16166 from karalabe/drop-dead
core: yeah, funny file, drop it
2018-02-22 16:31:28 +02:00
Balint Gabor
221486a291 Merge pull request #15919 from ethersphere/p2p-protocols-pr
p2p/protocols, p2p/testing: protocol abstraction and testing
2018-02-22 15:02:51 +01:00
Péter Szilágyi
0b3e23f636 core: yeah, funny file, drop it 2018-02-22 15:41:48 +02:00
Janos Guljas
a3a07350dc swarm, cmd/swarm: Merge branch 'master' into multiple-ens-endpoints 2018-02-22 14:23:17 +01:00
Péter Szilágyi
5be1085b6b Merge pull request #16165 from karalabe/faucet-twitter-api
cmd/faucet: resolve twitter user from final redirect
2018-02-22 13:30:40 +02:00
Péter Szilágyi
72c4c50777 cmd/faucet: resolve twitter user from final redirect 2018-02-22 13:20:36 +02:00
Anton Evangelatov
1e457b6599 p2p: don't send DiscReason when using net.Pipe (#16004) 2018-02-22 11:41:06 +01:00
Felix Lange
28b20cff4b p2p/protocols: gofmt -w -s 2018-02-22 11:37:57 +01:00
Guillaume Ballet
bb5349b154 whisper: Support for v2 has long been discontinued, remove it. (#16153) 2018-02-22 12:25:07 +02:00
Péter Szilágyi
724a915470 Merge pull request #16157 from nileshtrivedi/master
cmd/puppeth: Don't allow hyphen in network name. Fixes #16155
2018-02-22 09:56:59 +02:00
Nilesh Trivedi
085d3fbf72 cmd/puppeth: Don't allow hyphen in network name. Fixes #16155 2018-02-22 00:23:50 +05:30
Martin Holst Swende
45ce4dce3f Merge pull request #15776 from ProChain/master
accounts/abi: Fix the bug of mobile framework crashing
2018-02-21 19:21:41 +01:00
Martin Holst Swende
f54506ccf8 Merge pull request #15770 from holiman/abi_nostruct
accounts/abi: add another unpack interface
2018-02-21 15:14:07 +01:00
Martin Holst Swende
b585f76128 ethapi: prevent creating contract if no data is provided (#16108)
* ethapi: prevent creating contract if no data is provided

* internal/ethapi: downcase error for no data on contract creation
2018-02-21 16:10:18 +02:00
Dmitry Shulyak
14c76371ba p2p: when peer is removed remove it also from dial history (#16060)
This change removes a peer information from dialing history
when peer is removed from static list. It allows to force a
server to re-dial concrete peer if it is needed.

In our case we are running geth node on mobile devices, and
it is common for a network connection to flap on mobile.
Almost every time it flaps or network connection is changed
from cellular to wifi peers are disconnected with read
timeout. And usually it takes 30 seconds (default expiration
timeout) to recover connection with static peers after
connectivity is restored.

This change allows us to reconnect with peers almost
immediately and it seems harmless enough.
2018-02-21 15:03:26 +01:00
Péter Szilágyi
7d57824663 Merge pull request #16142 from karalabe/graceful-sigterm
cmd, console: support all termination signals
2018-02-21 15:50:34 +02:00
Péter Szilágyi
01507d9b9d cmd, console: support all termination signals 2018-02-21 15:23:10 +02:00
Pedro Pombeiro
34d94e22d9 whisper: Fix race condition in whisperv6/peer.go 2018-02-21 13:23:53 +01:00
Martin Holst Swende
61f2279bde abi: fix missing method on go 1.7/1.8 2018-02-21 12:27:50 +01:00
Martin Holst Swende
bd6ed23899 accounts/abi: harden unpacking against malicious input 2018-02-21 12:27:50 +01:00
Martin Holst Swende
08c5d4dd27 accounts/abi: address review concerns 2018-02-21 12:27:50 +01:00
Martin Holst Swende
f0f594d045 accounts/abi: Deduplicate code in unpacker 2018-02-21 12:27:50 +01:00
Martin Holst Swende
1ede68355d accounts/abi: add another unpack interface 2018-02-21 12:27:50 +01:00
steve greensill
5603715c06 README: add goreportcard.com badge to Readme (#16133)
* README: add goreportcard.com badge to Readme

* README: fix double github.com
2018-02-20 11:38:27 +02:00
Péter Szilágyi
46a5532ac5 VERSION, params: begin v1.8.2 release cycle 2018-02-19 11:38:36 +02:00
Péter Szilágyi
1e67410e88 params: release Geth v1.8.1 2018-02-19 11:35:31 +02:00
Felföldi Zsolt
1bdde620da les: fix light fetcher database race (#16103)
* les: fix light fetcher database race

* les: lightFetcher comments
2018-02-19 10:41:30 +02:00
Péter Szilágyi
06c5cae315 Merge pull request #16115 from nonsense/update_rjeczalik_notify
vendor: update rjeczalik/notify so that it compiles on go1.10
2018-02-19 10:39:28 +02:00
Janos Guljas
e07603bbc4 p2p/testing: check for all expectations in TestExchanges
Handle all expectations in ProtocolSession.TestExchanges in any
order that are received.
2018-02-17 23:42:28 +01:00
Péter Szilágyi
9fd76e33af Merge pull request #16109 from karalabe/p2p-bond-check
p2p/discover: validate bond against lastpong, not db presence
2018-02-17 18:47:44 +02:00
Anton Evangelatov
0a7cbd915a vendor: update rjeczalik/notify so that it compiles on go1.10 2018-02-17 14:35:59 +01:00
Felix Lange
aeedec4078 p2p/discover: s/lastPong/bondTime/, update TestUDP_findnode
I forgot to change the check in udp.go when I changed Table.bond to be
based on lastPong instead of node presence in db. Rename lastPong to
bondTime and add hasBond so it's clearer what this DB key is used for
now.
2018-02-16 21:29:20 +01:00
Péter Szilágyi
32301a4d6b p2p/discover: validate bond against lastpong, not db presence 2018-02-16 17:05:08 +02:00
cooganb
4e61ed02e2 swarm: add favicon for Swarm templates served by browser (#15958)
* swarm: added script to HTML header to create favicon addresses #153

* swarm: moved data blob direclty into link tag, removed script

* swarm: added favicon info to other html templates

* swarm: fixing test errors

* swarm: fixing favicon test

* swarm: fixing travis tests

* swarm: added script to HTML header to create favicon addresses #153

* swarm: moved data blob direclty into link tag, removed script

* swarm: added favicon info to other html templates

* swarm: fixing test errors

* swarm: fixing favicon test

* swarm: fixing travis tests
2018-02-15 16:24:20 +02:00
Guillaume Ballet
5f9b01a283 whisper: only use the node id as a p2p id, not for sending messages (#16102)
This is in preparation for the switch to libp2p: the ID generated
will be from a private key created with the help of libp2p's crypto
library, while Whisper will still use Go's default crypto libraries
for encrypting its messages. This change removes a conflict.

It shouldn't have any impact as the person receiving emails is
the user, not the node.
2018-02-15 14:43:48 +02:00
gluk256
fac6d9ce77 whisper: test timeout extended (#16088)
* whisper: timeout extended

* whisper: test updated

* whisper: test updated
2018-02-15 14:42:44 +02:00
Péter Szilágyi
2003b79779 Merge pull request #16095 from karalabe/les-lock
les: add missing lock around peer access
2018-02-15 13:02:36 +02:00
GuiltyMorishita
e2f2bb3e2e node: fix typo hvosts -> vhosts (#16096) 2018-02-15 12:38:39 +02:00
Péter Szilágyi
b92276c700 Merge pull request #16098 from holiman/fix_import
main: add gc flags to import-command
2018-02-15 12:34:33 +02:00
Martin Holst Swende
de93a9d437 main: add gc flags to import-command 2018-02-15 09:16:59 +01:00
ferhat elmas
dc7ca52b3b core: handle ignored error (#16065)
- according to implementation of `IntrinsicGas`
we can continue execution since problem will be detected
later. However, early return is future-proof for changes.
2018-02-14 22:02:51 +02:00
Péter Szilágyi
dfc5842a89 les: add missing lock around peer access 2018-02-14 21:09:20 +02:00
ferhat elmas
ff225db813 core/vm: remove unused hashing (#16075) 2018-02-14 15:41:05 +02:00
Felix Lange
752761cb57 params, VERSION: v1.8.1 unstable 2018-02-14 13:55:21 +01:00
Felix Lange
5f54075760 params: v1.8.0 stable 2018-02-14 13:51:30 +01:00
Péter Szilágyi
57bca0af8c containers/docker: bump legacy images to 1.8 branch (#16084) 2018-02-14 13:49:53 +01:00
Felix Lange
a5c0bbb4f4 all: update license information (#16089) 2018-02-14 13:49:11 +01:00
Péter Szilágyi
0544a43c13 Merge pull request #16085 from karalabe/p2p-fix-outofbounds
p2p/discover: fix out-of-bounds issue
2018-02-13 23:40:18 +02:00
Péter Szilágyi
20797348ca p2p/discover: fix out-of-bounds issue 2018-02-13 20:59:43 +02:00
Felix Lange
88f2839da4 travis.yml: work around Go 1.9.4 issue (#16082)
* travis.yml: work around Go 1.9.4 issue

* travis: workaround the workaround
2018-02-13 19:32:20 +02:00
Felix Lange
b007412db1 core: soften up state memory force-commit log messages (#16080)
Talk about "state" instead of "trie timing", "trie memory" and remove
the overzealous warning when the limit is just reached. Since the time
limit is always reached on slow machines, move the message to info level
so users don't freak out about internal details.
2018-02-13 15:12:55 +02:00
Péter Szilágyi
da41a7258d Merge pull request #16073 from karalabe/puppeth-unify-discovery
cmd/puppeth: unify discv4 and discv5 ports
2018-02-13 11:43:50 +02:00
Felföldi Zsolt
8d32c4b990 light: new CHTs (#16074) 2018-02-12 18:03:17 +02:00
Péter Szilágyi
12dab53495 cmd/puppeth: unify discv4 and discv5 ports 2018-02-12 16:27:53 +02:00
Péter Szilágyi
70fbc87379 Merge pull request #16071 from holiman/lintfix
node, rpc: fix linter issues
2018-02-12 15:16:47 +02:00
Martin Holst Swende
6c6247a690 node, rpc: fix linter issues 2018-02-12 14:12:55 +01:00
Martin Holst Swende
589b603a9b rpc: dns rebind protection (#15962)
* cmd,node,rpc: add allowedHosts to prevent dns rebinding attacks

* p2p,node: Fix bug with dumpconfig introduced in r54aeb8e4c0bb9f0e7a6c67258af67df3b266af3d

* rpc: add wildcard support for rpcallowedhosts + go fmt

* cmd/geth, cmd/utils, node, rpc: ignore direct ip(v4/6) addresses in rpc virtual hostnames check

* http, rpc, utils: make vhosts into map, address review concerns

* node: change log messages to use geth standard (not sprintf)

* rpc: fix spelling
2018-02-12 14:52:07 +02:00
Felix Lange
9123eceb0f p2p, p2p/discover: misc connectivity improvements (#16069)
* p2p: add DialRatio for configuration of inbound vs. dialed connections

* p2p: add connection flags to PeerInfo

* p2p/netutil: add SameNet, DistinctNetSet

* p2p/discover: improve revalidation and seeding

This changes node revalidation to be periodic instead of on-demand. This
should prevent issues where dead nodes get stuck in closer buckets
because no other node will ever come along to replace them.

Every 5 seconds (on average), the last node in a random bucket is
checked and moved to the front of the bucket if it is still responding.
If revalidation fails, the last node is replaced by an entry of the
'replacement list' containing recently-seen nodes.

Most close buckets are removed because it's very unlikely we'll ever
encounter a node that would fall into any of those buckets.

Table seeding is also improved: we now require a few minutes of table
membership before considering a node as a potential seed node. This
should make it less likely to store short-lived nodes as potential
seeds.

* p2p/discover: fix nits in UDP transport

We would skip sending neighbors replies if there were fewer than
maxNeighbors results and CheckRelayIP returned an error for the last
one. While here, also resolve a TODO about pong reply tokens.
2018-02-12 14:36:09 +02:00
Péter Szilágyi
1d39912a9b Merge pull request #16068 from karalabe/import-known-rolledback-blocks
core: force import known but rolled back blocks
2018-02-12 12:53:45 +02:00
Péter Szilágyi
69c1f2c2a7 core: force import known but rolled back blocks 2018-02-12 11:54:14 +02:00
ferhat elmas
52ad848b2e internal/build: fix usage of strings.TrimLeft (#16066) 2018-02-12 11:18:35 +02:00
Péter Szilágyi
4065695350 Merge pull request #16063 from karalabe/deprecate-ubuntu-zesty
build: deprecate zesty, add bionic PPA
2018-02-11 19:54:57 +02:00
Péter Szilágyi
969474f60a build: deprecate zesty, add bionic PPA 2018-02-11 19:07:11 +02:00
Péter Szilágyi
62ffec1be3 Merge pull request #16062 from karalabe/nodisable-fastsync
eth: only disable fast sync after success
2018-02-11 19:01:32 +02:00
Péter Szilágyi
57fd2da0fe eth: only disable fast sync after success 2018-02-11 17:25:00 +02:00
Péter Szilágyi
aa9432b816 Merge pull request #16061 from karalabe/downloader-nostate-ancestor-lookup
eth/downloader: don't require state for ancestor lookups
2018-02-11 16:39:09 +02:00
Péter Szilágyi
7a0019c63b les, light: fix CHT trie retrievals (#16039)
* les, light: fix CHT trie retrievals

* les, light: minor polishes, test remote CHT retrievals

* les, light: deterministic nodeset rlp, bloombits test skeleton

* les: add an event emission to the les bloombits test

* les: drop dead tester code
2018-02-11 14:57:46 +02:00
Péter Szilágyi
96dad6b6f6 eth/downloader: don't require state for ancestor lookups 2018-02-11 14:43:56 +02:00
Guillaume Ballet
5cf75a30c1 whisper: get wnode to work with v6 (#16051)
The bulk of the issue was to adapt to the new requirement
that a v6 filter has to either contain a symmertric key or
an asymmetric one.

This commits revert one of the fixes that I made to remove
a linter warning: unexporting NewSentMessage. This is not
really a problem as I have a cleanup in the pipe that will
solve this issue.
2018-02-10 15:35:32 +02:00
Felföldi Zsolt
2f849ade82 les: fix server panic when discovery disabled (#16055) 2018-02-10 14:33:52 +02:00
Chase Wright
a00f4a12a9 README: remove --fast and --cache flags and clarify default sync mode (#16043)
* Remove --fast flag and clarify default

`--fast` is no longer a flag it's `--syncmode "fast"` and that is the default

* Remove --cache flag

--cache=512 is no longer required as of 1.8 as the default has been increased

* README: Minor cache amount fix, mention Rinkeby
2018-02-10 12:50:14 +02:00
gluk256
42628ba7ed whisper: bloom filter refactoring (#16046)
* whisper: bloom filter refactoring

* whisper: fixed full node
2018-02-09 17:25:23 +02:00
gluk256
ccf8083537 whisper: Seal function fixed (#16048) 2018-02-09 17:25:03 +02:00
Felföldi Zsolt
c4712bf96b p2p/discv5: fix multiple discovery issues (#16036)
* p2p/discv5: add query delay, fix node address update logic, retry refresh if empty

* p2p/discv5: remove unnecessary ping before topic query

* p2p/discv5: do not filter local address from topicNodes

* p2p/discv5: remove canQuery()

* p2p/discv5: gofmt
2018-02-08 19:06:31 +02:00
cdetrio
2b4c7e9b37 params: update ropsten bootnodes (#16029)
* params: update ropsten bootnodes

* params: fix linter
2018-02-08 15:30:26 +02:00
Péter Szilágyi
03daf601c1 Merge pull request #16037 from karalabe/light-startup-polishes
eth, light: minor light client startup cleanups
2018-02-08 15:11:05 +02:00
Péter Szilágyi
eb07dbb079 eth, light: minor light client startup cleanups 2018-02-08 07:49:23 +02:00
gluk256
1a4e68721a Merge pull request #16022 from gballet/whisper-v6-investigate-macos-timeout
whisper: improve a log message to analyze a travis issue
2018-02-06 22:20:23 +02:00
Guillaume Ballet
806430a252 whisper: improve a log message to analyze a travis issue 2018-02-05 18:18:13 +01:00
Péter Szilágyi
55599ee95d core, trie: intermediate mempool between trie and database (#15857)
This commit reduces database I/O by not writing every state trie to disk.
2018-02-05 17:40:32 +01:00
Péter Szilágyi
59336283c0 Merge pull request #16020 from evertonfraga/patch-1
github: Replaces Wiki link [ci skip]
2018-02-05 17:58:47 +02:00
Ev
203440e813 github: Replaces Wiki link 2018-02-05 16:52:27 +01:00
Felföldi Zsolt
c3f238dd53 les: limit LES peer count and improve peer configuration logic (#16010)
* les: limit number of LES connections

* eth, cmd/utils: light vs max peer configuration logic
2018-02-05 15:41:53 +02:00
Martin Holst Swende
bc0666fb27 eth/downloader: fix #15858 by checking if downloader dropPeer function is set (#15992) 2018-02-05 15:38:06 +02:00
Péter Szilágyi
0662384d29 Merge pull request #16009 from holiman/db_handles
cmd/utils: fix #16006 by not lowering OS ulimit
2018-02-04 01:05:32 +02:00
Péter Szilágyi
b4e05adcc7 Merge pull request #16011 from karalabe/fix-bootnode-gofmt
params: fix bootnodes gofmt
2018-02-02 15:58:10 +02:00
Péter Szilágyi
efc9209158 params: fix bootnodes gofmt 2018-02-02 15:57:13 +02:00
Martin Holst Swende
ec28a58cc1 utils: fix #16006 by not lowering OS ulimit 2018-02-02 09:33:33 +01:00
Afri Schoedon
4dedde7beb params: Add Ropsten bootnodes (#16008) 2018-02-01 16:10:57 +02:00
Péter Szilágyi
fdb34b7a7c Merge pull request #15996 from karalabe/drop-redundant-methods
core, eth, les, light: get rid of redundant methods
2018-01-31 12:46:38 +02:00
Péter Szilágyi
07d4a02257 Merge pull request #15997 from karalabe/batch-reset-size
ethdb: reset the batch size too on reset
2018-01-30 19:18:42 +02:00
Péter Szilágyi
3e89b80ccb ethdb: reset the batch size too on reset 2018-01-30 19:12:28 +02:00
Martin Holst Swende
017b9f7eac core, ethdb: reuse database batches (#15989)
* leveldb: Update leveldb to 211f780 (poolfix)

* core, ethdb: reuse database batches
2018-01-30 19:03:31 +02:00
Péter Szilágyi
566d5c0777 core, eth, les, light: get rid of redundant methods 2018-01-30 18:42:00 +02:00
Felföldi Zsolt
6198c53e28 p2p/discv5: fix removeTicketRef cached ticket removal (#15995) 2018-01-30 18:01:22 +02:00
gluk256
a9e4a90d57 whisper: change the whisper message format so as to add the payload size (#15870)
* whisper: message format changed

* whisper: tests fixed

* whisper: style fixes

* whisper: fixed names, fixed failing tests

* whisper: fix merge issue in #15870

Occured while using the github online merge tool. Lesson learned.

* whisper: fix a gofmt error for #15870
2018-01-30 10:55:08 +02:00
Martin Holst Swende
59a852e418 vendor: update leveldb to 211f780 (poolfix) (#15988) 2018-01-29 16:17:59 +02:00
Guillaume Ballet
dd7a715d73 internal: fix a typo that caused a lint error on travis (#15987) 2018-01-29 15:35:05 +02:00
Martin Holst Swende
722bac84fa ethapi: add personal.signTransaction (#15971)
* ethapi: add personal.signTransaction

* ethapi: refactor to minimize duplicate code

* ethapi: make nonce,gas,gasPrice obligatory in signTransaction
2018-01-26 19:32:43 +02:00
Felföldi Zsolt
23bca0f374 les: fix TxStatusMsg RLP coding (#15974) 2018-01-26 19:30:45 +02:00
Guillaume Ballet
367c329b88 whisper: remove linter warnings (#15972)
* whisper: fixes warnings from the code linter

* whisper: more non-API-breaking changes

The remaining lint errors are because of auto-generated
files and one is because an exported function has a non-
exported return type. Changing this would break the API,
and will be part of another commit for easier reversal.

* whisper: un-export NewSentMessage to please the linter

This is an API change, which is why it's in its own commit.
This change was initiated after the linter complained that
the returned type wasn't exported. I chose to un-export
the function instead of exporting the type, because that
type is an implementation detail that I would like to
change in the near future to make the code more
readable and with an increased coverage.

* whisper: update gencodec output after upgrading it to new lint standards
2018-01-26 13:45:10 +02:00
b00ris
2ef3815af4 whisper: fix empty topic (#15811)
* whisper: fix empty topic

* whisper: add check to matchSingleTopic

* whisper: add tests

* whisper: fix gosimple

* whisper: added lastTopicByte const
2018-01-26 13:41:53 +02:00
Miguel Mota
4dd0727c39 accounts: fix comment typo (#15977) 2018-01-26 13:33:27 +02:00
waymobetta
8f6990dc7d accounts/abi/bind/backends: fix comment typo (#15914) 2018-01-25 12:26:14 +02:00
Felföldi Zsolt
c335821479 cmd, params: update discovery v5 bootnodes (#15954) 2018-01-25 12:25:00 +02:00
Steven Roose
952482d5e4 rpc: Support specifying HTTP client in RPC dialing (#15836)
* rpc: Support specifying HTTP client in RPC dialing

Adds a minimal interface that captures http.Client and adds a new method
rpc.DialHTTPClient that takes a client using that interface. The existing
rpc.DialHTTP method is then alternatively implemented by using the new
rpc.DialHTTPClient method provided with a standard *http.Client.

* rpc: fix minor doc typos
2018-01-24 10:59:15 +02:00
Péter Szilágyi
5c83a4e5dd Merge pull request #15832 from karalabe/abigen-events
accounts/abi/bind: support event filtering in abigen
2018-01-24 10:55:24 +02:00
Péter Szilágyi
1bf508b449 accounts/abi/bind: support event filtering in abigen 2018-01-24 10:54:13 +02:00
Kurkó Mihály
05ade19302 dashboard: CPU, memory, diskIO and traffic on the footer (#15950)
* dashboard: footer, deep state update

* dashboard: resolve asset path

* dashboard: prevent state update on every reconnection

* dashboard: fix linter issue

* dashboard, cmd: minor UI fix, include commit hash

* dashboard: gitCommit renamed to commit

* dashboard: move the geth version to the right, make commit optional

* dashboard: memory, traffic and CPU on footer

* dashboard: fix merge

* dashboard: CPU, diskIO on footer

* dashboard: rename variables, use group declaration

* dashboard: docs
2018-01-23 22:51:04 +02:00
Felföldi Zsolt
ec96216d16 Chain indexer fix + new CHT (#15934)
* core, light: fix chain indexer bug

* light: add new CHT
2018-01-23 13:10:49 +02:00
croath
a6787a6308 accounts/abi: fix the output at the beginning instead of making a workaround 2018-01-23 19:10:23 +08:00
Felföldi Zsolt
397c6cde1e p2p/discv5: fix topic register panic at shutdown (#15946) 2018-01-23 12:53:09 +02:00
Péter Szilágyi
302c17c36a Merge pull request #15948 from holiman/addr_v5_bootnode
p2p/discv5: logs info about discv5 node info at bind time
2018-01-23 12:27:03 +02:00
Felix Lange
924065e19d consensus/ethash: improve cache/dataset handling (#15864)
* consensus/ethash: add maxEpoch constant

* consensus/ethash: improve cache/dataset handling

There are two fixes in this commit:

Unmap the memory through a finalizer like the libethash wrapper did. The
release logic was incorrect and freed the memory while it was being
used, leading to crashes like in #14495 or #14943.

Track caches and datasets using simplelru instead of reinventing LRU
logic. This should make it easier to see whether it's correct.

* consensus/ethash: restore 'future item' logic in lru

* consensus/ethash: use mmap even in test mode

This makes it possible to shorten the time taken for TestCacheFileEvict.

* consensus/ethash: shuffle func calc*Size comments around

* consensus/ethash: ensure future cache/dataset is in the lru cache

* consensus/ethash: add issue link to the new test

* consensus/ethash: fix vet

* consensus/ethash: fix test

* consensus: tiny issue + nitpick fixes
2018-01-23 12:05:30 +02:00
Martin Holst Swende
48641d7308 p2p/discv5: logs info about discv5 node info at bind time 2018-01-23 08:50:11 +01:00
Péter Szilágyi
5d4267911a Merge pull request #15941 from karalabe/fix-header-reorg-order
core: sorted reorg insertion order for proper head header updating
2018-01-22 15:38:30 +02:00
Felföldi Zsolt
92580d69d3 p2p, p2p/discover, p2p/discv5: implement UDP port sharing (#15200)
This commit affects p2p/discv5 "topic discovery" by running it on
the same UDP port where the old discovery works. This is realized
by giving an "unhandled" packet channel to the old v4 discovery
packet handler where all invalid packets are sent. These packets
are then processed by v5. v5 packets are always invalid when
interpreted by v4 and vice versa. This is ensured by adding one
to the first byte of the packet hash in v5 packets.

DiscoveryV5Bootnodes is also changed to point to new bootnodes
that are implementing the changed packet format with modified
hash. Existing and new v5 bootnodes are both running on different
ports ATM.
2018-01-22 13:38:34 +01:00
Péter Szilágyi
84be009154 core: sorted reorg insertion order for proper head header updating 2018-01-22 14:11:07 +02:00
zelig
407339085f p2p/protocols, p2p/testing: protocol abstraction and testing 2018-01-18 10:53:47 +01:00
Péter Szilágyi
02aeb3d766 Merge pull request #15902 from shapeshed/patch-2
core/vm: Fix comment typo
2018-01-16 18:23:41 +02:00
George Ornbo
370dca4491 core/vm: Fix comment typo 2018-01-16 15:47:33 +00:00
Felix Lange
f08cd94fb7 cmd/ethkey: fix formatting, review nits (#15807)
This commit:

- Adds a --msgfile option to read the message to sign from a file
  instead of command line argument.
- Adds a unit test for signing subcommands.
- Removes some weird whitespace in the code.
2018-01-16 15:42:41 +01:00
Péter Szilágyi
216e584899 Revert "trie: make fullnode children hash calculation concurrently (#15131)" (#15889)
This reverts commit 0f7fbb85d6.
2018-01-15 15:32:14 +02:00
Jim McDonald
18a7d31338 miner: avoid unnecessary work (#15883) 2018-01-15 12:57:06 +02:00
Kurkó Mihály
938cf4528a dashboard: deep state update, version in footer (#15837)
* dashboard: footer, deep state update

* dashboard: resolve asset path

* dashboard: remove bundle.js

* dashboard: prevent state update on every reconnection

* dashboard: fix linter issue

* dashboard, cmd: minor UI fix, include commit hash

* remove geth binary

* dashboard: gitCommit renamed to commit

* dashboard: move the geth version to the right, make commit optional

* dashboard: commit limited to 7 characters

* dashboard: limit commit length on client side

* dashboard: run go generate
2018-01-15 11:20:00 +02:00
Péter Szilágyi
81ad8f665d Merge pull request #15869 from Magicking/ethstats-reporting-fix
ethstats: Fix ethstats reporting while syncing
2018-01-15 10:36:43 +02:00
Magicking
90e5744d6f ethstats: Fix ethstats reporting while syncing 2018-01-12 18:30:38 +01:00
Péter Szilágyi
3f40b22dac Merge pull request #15863 from karalabe/light-miner-error
cmd/geth: user friendly light miner error
2018-01-12 17:30:19 +02:00
gluk256
fd869dc839 whisper/whisperv6: implement pow/bloom exchange protocol (#15802)
This is the main feature of v6.
2018-01-12 12:11:22 +01:00
Péter Szilágyi
bd0dbfa2a8 cmd/geth: user friendly light miner error 2018-01-12 11:59:18 +02:00
Ricardo Domingos
56152b31ac common/fdlimit: Move fdlimit files to separate package (#15850)
* common/fdlimit: Move fdlimit files to separate package

When go-ethereum is used as a library the calling program need to set
the FD limit.

This commit extract fdlimit files to a separate package so it can be
used outside of go-ethereum.

* common/fdlimit: Remove FdLimit from functions signature

* common/fdlimit: Rename fdlimit functions
2018-01-11 22:55:21 +02:00
Jean-André Santoni
023769d9d4 travis.yml: remove alias for 'cd' to avoid hang on macOS (#15849)
This works around travis-ci/travis-ci#8703.
2018-01-11 16:02:01 +01:00
Nick Johnson
b06e20bc7c eth/gasprice: set default percentile to 60%, count blocks instead of transactions (#15828)
The first should address a long term issue where we recommend a gas
price that is greater than that required for 50% of transactions in
recent blocks, which can lead to gas price inflation as people take
this figure and add a margin to it, resulting in a positive feedback
loop.
2018-01-10 13:57:36 +01:00
gary rong
3a5a5599dd consensus/ethash: fix byzantium difficulty comment typo (#15842) 2018-01-10 10:58:03 +02:00
Felföldi Zsolt
83d1657444 les: fix les/1 CHT compatibility issue (#15692) 2018-01-09 11:41:59 +01:00
Felix Lange
9d06026c19 all: regenerate codecs with gencodec commit 90983d99de (#15830)
Fixes #15777 because null is now allowed for hexutil.Bytes.
2018-01-08 15:13:22 +02:00
Felix Lange
5c2f1e0014 all: update generated code (#15808)
* core/types, core/vm, eth, tests: regenerate gencodec files

* Makefile: update devtools target

Install protoc-gen-go and print reminders about npm, solc and protoc.
Also switch to github.com/kevinburke/go-bindata because it's more
maintained.

* contracts/ens: update contracts and regenerate with solidity v0.4.19

The newer upstream version of the FIFSRegistrar contract doesn't set the
resolver anymore. The resolver is now deployed separately.

* contracts/release: regenerate with solidity v0.4.19

* contracts/chequebook: fix fallback and regenerate with solidity v0.4.19

The contract didn't have a fallback function, payments would be rejected
when compiled with newer solidity. References to 'mortal' and 'owned'
use the local file system so we can compile without network access.

* p2p/discv5: regenerate with recent stringer

* cmd/faucet: regenerate

* dashboard: regenerate

* eth/tracers: regenerate

* internal/jsre/deps: regenerate

* dashboard: avoid sed -i because it's not portable

* accounts/usbwallet/internal/trezor: fix go generate warnings
2018-01-08 14:15:57 +02:00
Russ Cox
a139041d40 dashboard: use balanced trees to include binary data (#15813)
* go-ethereum/dashboard: update assets.go

Use current rsc/go-bindata instead of jteeuwen/go-bindata, to get
balanced tree in very long string concatenations.
This works around problems in current Go distributions.

For golang/go#23222.

* dashboard: run last two go:generate steps for linter
2018-01-05 13:02:15 +02:00
Felix Lange
1c2378b926 tests: update to upstream commit 2bb0c3da3b (#15806)
Also raise traceLimit once again and print the VM
error and output on failure.
2018-01-04 13:18:30 +01:00
Péter Szilágyi
ae71da1b03 eth: fix tracer panic when running without configs + reexec (#15799) 2018-01-04 12:58:11 +01:00
Evangelos Pappas
7a59a9380e cmd/utils: handle git commit a bit safer for user specified strings (#15790)
* cmd/utils/flags.go: Applying a String len guard for the gitCommit param of the NewApp()

* cmd/utils: remove redundant clause in if condition
2018-01-03 18:18:53 +02:00
Péter Szilágyi
762f3a48a0 Merge pull request #15466 from karalabe/uint64-gas-limit
all: switch gas limits from big.Int to uint64
2018-01-03 16:53:06 +02:00
Felix Lange
b47285f1cf vendor: update github.com/rjeczalik/notify (#15801) 2018-01-03 16:50:33 +02:00
Péter Szilágyi
6f69cdd109 all: switch gas limits from big.Int to uint64 2018-01-03 14:45:35 +02:00
Furkan KAMACI
b8caba9709 various: remove redundant parentheses (#15793) 2018-01-03 14:14:47 +02:00
Felix Lange
9d48dbf5c2 eth: revert tracer preimage recording (#15800)
This reverts commits 85a1eda59e (#15792) and c495bca4ad (#15787)
because they introduce database writes during tracing.
2018-01-03 11:58:25 +01:00
Felix Lange
85a1eda59e eth: uncaptialize tracer preimage error message (#15792)
* eth: uncaptialize tracer preimage error message

* eth: improve very important error message
2018-01-03 10:53:09 +02:00
Richard Hart
72e70bcec2 console: remove comment about 'invalid' input (#15735)
All inputs are saved into history, including 'invalid' inputs.
2018-01-02 13:00:13 +01:00
ferhat elmas
5866626b08 core, p2p/discv5: use time.NewTicker instead of time.Tick (#15747) 2018-01-02 12:50:46 +01:00
cdetrio
c495bca4ad eth: enable preimage recording when tracing (#15787) 2018-01-02 12:49:17 +01:00
Péter Szilágyi
413cc5b0c8 cmd/geth: remove trailing newline in license command (#15782) 2018-01-02 12:48:19 +01:00
Péter Szilágyi
d2533d0efb vendor: update github.com/rjeczalik/notify for go1.10 (#15785) 2018-01-02 11:41:47 +01:00
Péter Szilágyi
3e0113fff4 build: set CC through a command-line flag (#15784)
This avoids setting CC for the go run invocation, which fails on go1.10.
2018-01-02 11:40:56 +01:00
Péter Szilágyi
9c42a41ed8 eth/downloader: avoid hidden reference to finished statesync request (#15545) 2018-01-02 11:38:26 +01:00
Péter Szilágyi
2fe07c203e build: fix version comparison for go1.10 and beyond (#15781) 2018-01-02 11:28:07 +01:00
Deepak Sharma
6882943e39 containers/docker: change docker images to go1.9 (#15789) 2018-01-02 11:27:33 +01:00
Péter Szilágyi
b98aa3b4f1 whisper/whisper2: fix Go 1.10 vet issues on type mismatches (#15783) 2018-01-02 11:13:24 +01:00
Alex Wu
6cd6b921ac crypto: ensure private keys are < N (#15745)
Fixes #15744
2018-01-02 10:55:03 +01:00
sunxiaojun2014
908faf8cd7 consensus/ethash: fix overdue link (#15786) 2017-12-31 13:38:39 +02:00
croath
88e67c552e accounts/abi: add a test case for unpacking mobile interfaces 2017-12-31 19:12:55 +08:00
Péter Szilágyi
b9731767af accounts/abi: handle named ouputs prefixed with underscores (#15766)
* accounts/abi: handle named ouputs prefixed with underscores

* accounts/abi: handle collinding outputs for struct unpacks

* accounts: handle purely underscore output names
2017-12-29 23:20:02 +02:00
Anton Evangelatov
36a10875c8 p2p/enr: initial implementation (#15585)
Initial implementation of ENR according to ethereum/EIPs#778
2017-12-29 21:18:51 +01:00
croath
e7cd627d93 accounts/abi: fix for one output interface crashing 2017-12-29 19:56:23 +08:00
Péter Szilágyi
f7ca03ae87 eth, les, light: expose chain config in les node info too (#15732) 2017-12-28 14:18:34 +01:00
Péter Szilágyi
c15d76a40f p2p/discv5: fix reg lookup, polish code, use logger (#15737) 2017-12-28 14:17:03 +01:00
Sorin Neacsu
5369a5c54d rpc: allow OPTIONS requests without Content-Type (#15759)
Fixes #15740
2017-12-28 14:15:33 +01:00
Martin Holst Swende
9d187f0238 Merge pull request #15731 from holiman/revamp_abi
accounts/abi refactor
2017-12-22 20:59:41 +01:00
Martin Holst Swende
c095c87e11 accounts/abi: merging of https://github.com/ethereum/go-ethereum/pull/15452 + lookup by id 2017-12-22 19:26:57 +01:00
Martin Holst Swende
73d4a57d47 acounts/abi: refactor abi, generalize abi pack/unpack to Arguments 2017-12-22 19:26:52 +01:00
gary rong
5f8888e116 accounts, consensus, core, eth: make chain maker consensus agnostic (#15497)
* accounts, consensus, core, eth: make chain maker consensus agnostic

* consensus, core: move CalcDifficulty to Engine interface

* consensus: add docs for calcDifficulty function

* consensus, core: minor comment fixups
2017-12-22 14:37:50 +02:00
Kurkó Mihály
9dbb8ef4aa dashboard: integrate Flow, sketch message API (#15713)
* dashboard: minor design change

* dashboard: Flow integration, message API

* dashboard: minor polishes, exclude misspell linter
2017-12-21 17:54:38 +02:00
Péter Szilágyi
52f4d6dd78 Merge pull request #15730 from karalabe/puppeth-expose-faucet-http
cmd/puppeth: fix faucet 502 error due to non-exposed HTTP port
2017-12-21 17:36:27 +02:00
Péter Szilágyi
e4aa882ec5 cmd/puppeth: fix faucet 502 error due to non-exposed HTTP port 2017-12-21 17:25:42 +02:00
gluk256
38b1e8ee20 whisper/whisperv6: PoW requirement (#15701)
New Whisper-level message introduced (PoW requirement),
corresponding logic added, plus some tests.
2017-12-21 15:17:27 +01:00
Robert Zaremba
81d4cafb32 accounts/abi: add unpack into array test 2017-12-21 15:14:50 +01:00
Robert Zaremba
1afca33eac accounts/abi: add Method Unpack tests
+ Reworked Method Unpack tests into more readable components
+ Added Method Unpack into slice test
2017-12-21 15:14:50 +01:00
Robert Zaremba
95461e8b22 accounts/abi: satisfy most of the linter warnings
+ adding missing comments
+ small cleanups which won't significantly change
  function body.
+ unify Method receiver name
2017-12-21 15:14:50 +01:00
Robert Zaremba
0ed8b838a9 accounts/abi: fix event unpack into slice
+ The event slice unpacker doesn't correctly extract element from the
slice. The indexed arguments are not ignored as they should be
(the data offset should not include the indexed arguments).

+ The `Elem()` call in the slice unpack doesn't work.
The Slice related tests fails because of that.

+ the check in the loop are suboptimal and have been extracted
out of the loop.

+ extracted common code from event and method tupleUnpack
2017-12-21 15:14:50 +01:00
Robert Zaremba
9becba5540 accounts/abi: fix event tupleUnpack
Event.tupleUnpack doesn't handle correctly Indexed arguments,
hence it can't unpack an event with indexed arguments.
2017-12-21 15:14:50 +01:00
Robert Zaremba
3511904aad accounts/abi: adding event unpacker tests 2017-12-21 15:14:50 +01:00
Martin Holst Swende
b0d41e386e Merge pull request #15285 from yondonfu/abi-offset-fixed-arrays
accounts/abi: include fixed array size in offset for dynamic type
2017-12-21 14:42:03 +01:00
Péter Szilágyi
91c3362315 Merge pull request #15729 from karalabe/faucet-fix-twitter
cmd/faucet: fix removal of Twitter zlib compression
2017-12-21 15:32:10 +02:00
lash
14852810b4 cmd/utils: add check on fd hard limit, skip test if below target (#15684)
* cmd/utils: Add check on hard limit, skip test if below target

* cmd/utils: Cross platform compatible fd limit test

* cmd/utils: Remove syscall.Rlimit in test

* cmd/utils: comment fd utility method
2017-12-21 15:30:44 +02:00
Janoš Guljaš
542d51895f swarm/api: url scheme bzz-hash to get hashes of swarm content (#15238) (#15715)
* swarm/api: url scheme bzz-hash to get hashes of swarm content (#15238)

Update URI to support bzz-hash scheme and handle such HTTP requests by
responding with hash of the content as a text/plain response.

* swarm/api: return hash of the content for bzz-hash:// requests

* swarm/api: revert "return hash of the content for bzz-hash:// requests"

Return hashes of the content that would be returned by bzz-raw
request.

* swarm/api/http: handle error in TestBzzGetPath

* swarm/api: remove extra blank line in comment
2017-12-21 14:47:10 +02:00
Péter Szilágyi
68651a2329 cmd/faucet: fix removal of Twitter zlib compression 2017-12-21 14:14:24 +02:00
Péter Szilágyi
5258785c81 cmd, core, eth/tracers: support fancier js tracing (#15516)
* cmd, core, eth/tracers: support fancier js tracing

* eth, internal/web3ext: rework trace API, concurrency, chain tracing

* eth/tracers: add three more JavaScript tracers

* eth/tracers, vendor: swap ottovm to duktape for tracing

* core, eth, internal: finalize call tracer and needed extras

* eth, tests: prestate tracer, call test suite, rewinding

* vendor: fix windows builds for tracer js engine

* vendor: temporary duktape fix

* eth/tracers: fix up 4byte and evmdis tracer

* vendor: pull in latest duktape with my upstream fixes

* eth: fix some review comments

* eth: rename rewind to reexec to make it more obvious

* core/vm: terminate tracing using defers
2017-12-21 13:56:11 +02:00
Péter Szilágyi
1a5425779b Merge pull request #15727 from karalabe/rinkeby-akasha-bootnode
params: add Rinkeby bootnode from Akasha
2017-12-21 13:54:46 +02:00
Péter Szilágyi
a28390542c params: add Rinkeby bootnode from Akasha 2017-12-21 13:19:42 +02:00
Steven Roose
eeb53bc143 cmd/ethkey: new command line tool for keys (#15438)
ethkey is a new tool that serves as a command line interface to
the basic key management functionalities of geth. It currently
supports:
 
 - generating keyfiles
 - inspecting keyfiles (print public and private key)
 - signing messages
 - verifying signed messages
2017-12-21 11:36:05 +01:00
Bob Glickstein
e21aa0fda3 accounts/abi: remove check for len%32==0 when unpacking events (#15670)
This change inlines the logic of bytesAreProper at its sole
callsite, ABI.Unpack, and applies the multiple-of-32 test only in
the case of unpacking methods. Event data is not required to be a
multiple of 32 bytes long.
2017-12-21 10:59:14 +01:00
gluk256
9f1007e554 whisper/whisperv6: message bundling (#15666)
Changed the communication protocol for ordinary message,
according to EIP 627. Messages will be send in bundles, i.e.
array of messages will be sent instead of single message.
2017-12-21 10:31:44 +01:00
Péter Szilágyi
4b939c23e4 appveyor: bump Go to 1.9.2 (#15726) 2017-12-21 11:30:44 +02:00
Péter Szilágyi
7138de7b55 core: silence txpool reorg warning (annoying on import) (#15725) 2017-12-21 10:20:10 +02:00
Kurkó Mihály
b4cf57a581 core: fix typos (#15720) 2017-12-20 19:08:51 +02:00
Dmitry Shulyak
da58afcea0 accounts/abi: update array length after parsing array (#15618)
Fixes #15617
2017-12-20 15:09:23 +01:00
Felix Lange
ce823c9f84 crypto: ensure that VerifySignature rejects malleable signatures (#15708)
* crypto: ensure that VerifySignature rejects malleable signatures

It already rejected them when using libsecp256k1, make sure the nocgo
version does the same thing.

* crypto: simplify check

* crypto: fix build
2017-12-20 14:30:00 +02:00
Péter Szilágyi
5e1581c2c3 core: fix panic when stat-ing a tx from a queue-only account (#15714) 2017-12-20 12:34:43 +02:00
Janos Guljas
820cf09c98 cmd/swarm: return error early in buildConfig function 2017-12-19 23:51:09 +01:00
Armin Braun
50df2b78be console: create datadir at startup (#15700)
Fixes #15672 by creating the datadir when creating the
console. This prevents failing to save the history if no datadir
exists.
2017-12-19 13:21:03 +01:00
Janos Guljas
dd5ae4fd8e cmd/swarm: add validation for EnsAPIs configuration parameter 2017-12-19 11:47:26 +01:00
Janoš Guljaš
c786f75389 swarm: bzz-list, bzz-raw and bzz-immutable schemes (#15667)
* swarm/api: url scheme bzz-list for getting list of files from manifest

Replace query parameter list=true for listing all files contained
in a swarm manifest with a new URL scheme bzz-list.

* swarm: replaace bzzr and bzzi schemes with bzz-raw and bzz-immutable

New URI Shemes are added and old ones are deprecated, but not removed.
Old Schemes bzzr and bzzi are functional for backward compatibility.

* swarm/api: completely remove bzzr and bzzi schemes

Remove old schemes in favour of bzz-raw and
bzz-immutable.

* swarm/api: revert "completely remove bzzr and bzzi schemes"

Keep bzzr and bzzi schemes for backward compatibility. At least
until 0.3 swarm release.
2017-12-19 10:49:30 +02:00
Péter Szilágyi
7f9d94fe9a Merge pull request #15693 from zsfelfoldi/wait_nopeers
contracts/release: do not print error log if les backend has no peers
2017-12-19 10:45:02 +02:00
Yondon Fu
cf7aba36c8 accounts/abi: update array type check in method.go. Add more packing tests 2017-12-18 21:16:25 -05:00
Yondon Fu
3857cdc267 Merge branch 'master' into abi-offset-fixed-arrays 2017-12-18 17:17:41 -05:00
Janos Guljas
0d6a735a72 swarm/api: implement NoResolverError with information about TLD
MultiResolver needs to provide information about TLD that has
no resolver configured for.
2017-12-18 23:07:48 +01:00
Zsolt Felfoldi
48648bc2f8 contracts/release: do not print error log if les backend has no peers 2017-12-18 16:26:17 +01:00
Janos Guljas
c0a4d9e1e6 cmd/swarm, swarm: disable ENS API by default
Specifying ENS API CLI flag, env variable or configuration
field is required for ENS resolving. Backward compatibility is
preserved with --ens-api="" CLI flag value.
2017-12-18 16:22:39 +01:00
Péter Szilágyi
fe070ab5c3 Merge pull request #15674 from chfast/vm-no-snapshot-param
core/vm: Remove snapshot param from Interpreter.Run()
2017-12-18 16:16:59 +02:00
Felix Lange
8c33ac10bf internal/ethapi: support "input" in transaction args (#15640)
The tx data field is called "input" in returned objects and "data" in
argument objects. Make it so "input" can be used, but bail if both
are set.
2017-12-18 12:50:21 +01:00
Péter Szilágyi
3b79bac05b Merge pull request #15698 from original-brownbear/15668
accounts/keystore: Improved error message
2017-12-18 13:43:10 +02:00
Armin
afc2039f22 accounts/keystore: Improved error message
* Fix for #15668
2017-12-18 12:28:34 +01:00
Péter Szilágyi
13db4af345 Merge pull request #15696 from ferhatelmas/p2p-goroutine-leak
p2p/discover: fix leaked goroutine in data expiration
2017-12-18 10:59:10 +02:00
Péter Szilágyi
64ee3e92ea Merge pull request #15686 from sorin/sorin-geth-attach-rinkeby
cmd/geth: add support for geth --rinkeby attach
2017-12-18 10:28:09 +02:00
ferhat elmas
afa3c72c40 p2p/discover: fix leaked goroutine in data expiration 2017-12-18 09:16:54 +01:00
Sorin Neacsu
1d7d7f57d0 cmd/geth: add support for geth --rinkeby attach 2017-12-15 13:31:10 -08:00
Paweł Bylica
fb5f25eeee core/vm: Remove snapshot param from Interpreter.Run() 2017-12-15 13:33:35 +01:00
Felix Lange
c6069a627c crypto, crypto/secp256k1: add CompressPubkey (#15626)
This adds the inverse to DecompressPubkey and improves a few minor
details in crypto/secp256k1.
2017-12-15 10:40:09 +01:00
Péter Szilágyi
1f2176dedc Merge pull request #15679 from shapeshed/patch-1
crypto: Fix comment typo
2017-12-15 01:24:19 +02:00
George Ornbo
7bb2a489b2 crypto: Fix comment typo 2017-12-14 21:55:18 +00:00
rhaps107
e9971d356b internal/ethapi: don't crash for missing receipts
Fixes #15408
Fixes #14432
2017-12-14 13:24:34 +01:00
Janos Guljas
47a8014559 cmd/swarm: Merge branch 'master' into multiple-ens-endpoints
Fix a conflict in cmd/swarm envVarsOverride function.
2017-12-14 10:36:12 +01:00
Péter Szilágyi
5129ef22c2 Merge pull request #15629 from holiman/relax_futuretime
consensus/ethash: relax requirements when determining future-blocks
2017-12-14 11:28:42 +02:00
Janos Guljas
19982f9467 swarm, cmd/swarm: Merge branch 'master' into multiple-ens-endpoints
Merge with changes that implement config file PR #15548.

Field *EnsApi string* in swarm/api.Config is replaced with
*EnsAPIs []string*.

A new field *EnsDisabled bool* is added to swarm/api.Config for
easy way to disable ENS resolving with config file.

Signature of function swarm.NewSwarm is changed and simplified.
2017-12-13 10:40:39 +01:00
Felix Lange
3654aeaa4f p2p/simulations: fix gosimple nit (#15661) 2017-12-13 03:15:27 +01:00
Vitaly V
f258a21a63 rpc: use method constants instead of literal strings (#15652) 2017-12-12 19:12:32 +01:00
holisticode
fd777bb210 p2p/simulations: add mocker functionality (#15207)
This commit adds mocker functionality to p2p/simulations. A
mocker allows to starting/stopping of nodes via the HTTP API.
2017-12-12 19:10:41 +01:00
Zach
3da1bf8ca1 all: use gometalinter.v2, fix new gosimple issues (#15650) 2017-12-12 19:05:47 +01:00
yoza
bbea4b2b53 internal/ethapi: fix typo in comment (#15659) 2017-12-12 18:55:39 +01:00
holisticode
32516c768e cmd/swarm: add config file (#15548)
This commit adds a TOML configuration option to swarm. It reuses
the TOML configuration structure used in geth with swarm
customized items.

The commit:

* Adds a "dumpconfig" command to the swarm executable which
  allows printing the (default) configuration to stdout, which
  then can be redirected to a file in order to customize it.
* Adds a "--config <file>" option to the swarm executable which will
  allow to load a configuration file in TOML format from the
  specified location in order to initialize the Swarm node The
  override priorities are like follows: environment variables
  override command line arguments override config file override
  default config.
2017-12-11 22:56:06 +01:00
Felix Lange
1a32bdf92c crypto: fix error check in toECDSA (#15632)
With this change,

    key, err := crypto.HexToECDSA("000000...")
    
returns nil key and an error instead of a non-nil key with nil X
and Y inside. Issue found by @guidovranken.
2017-12-11 22:49:09 +01:00
Felix Lange
2499b1b139 rlp: fix string size check in readKind (#15625)
Issue found by @guidovranken
2017-12-11 22:47:10 +01:00
Guillaume Ballet
e7610eadfe whisper: sym encryption message padding includes salt (#15631)
Now that the AES salt has been moved to the payload, padding must
be adjusted to hide it, lest an attacker guesses that the packet
uses symmetric encryption.
2017-12-11 12:32:58 +01:00
Michael Ruminer
732f5468d3 eth: make tracing API errors more user friendly (#15589) 2017-12-09 23:47:13 +01:00
Alejandro Isaza
bbfe0b8d04 mobile: Add GetSign to BigInt (#15558) 2017-12-09 23:45:46 +01:00
Péter Szilágyi
46e5583993 cmd/utils, eth: init etherbase from within eth (#15528) 2017-12-09 23:42:23 +01:00
Guillaume Ballet
bf62acf033 whisper/whisperv6: remove Version from the envelope (#15621) 2017-12-08 16:08:56 +01:00
Sorin Neacsu
586198ccea console: add admin.clearHistory command (#15614) 2017-12-08 15:14:14 +01:00
Guillaume Ballet
d95962cd5d whisper/whisperv6: remove aesnonce (#15578)
As per EIP-627, the salt for symmetric encryption is now
part of the payload. This commit does that.
2017-12-08 11:40:59 +01:00
Martin Holst Swende
79d5e5593f consensus/ethash: relax requirements when determining future-blocks 2017-12-08 10:06:16 +01:00
Felix Lange
b5874273ce travis.yml: avoid submodules on builders without tests (#15620)
Also remove installation steps for fuse and golang.org/x/tools/cmd/cover 
because they're not required anymore.
2017-12-07 15:49:35 +01:00
Airead
8092106abc core/types: fix typo in comment (#15619) 2017-12-07 10:06:44 +01:00
Benoit Verkindt
eab2201f80 eth: return rlp-decoded values from debug_storageRangeAt (#15476)
Fixes #15196
2017-12-06 16:42:16 +01:00
Felix Lange
e85b68ef53 crypto: add DecompressPubkey, VerifySignature (#15615)
We need those operations for p2p/enr.

Also upgrade github.com/btcsuite/btcd/btcec to the latest version
and improve BenchmarkSha3. The benchmark printed extra output 
that confused tools like benchstat and ignored N.
2017-12-06 16:07:08 +01:00
Sorin Neacsu
6e613cf3de cmd/geth: add support for geth attach --testnet (#15597) 2017-12-05 11:17:38 +01:00
Janos Guljas
1dc19de5da swarm/api: use path.Ext instead strings.LastIndex in MultiResolver.Resolve 2017-12-04 22:56:52 +01:00
Janos Guljas
e451b65fae swarm: deprecate --ens-addr CLI flag with a warning message 2017-12-04 22:41:21 +01:00
Janos Guljas
3732c15faa swarm/api: remove unneeded blank assignement 2017-12-04 22:32:33 +01:00
Janos Guljas
a758b5cf7a swarm/api: initialize map with make to comply with the convention 2017-12-04 22:31:00 +01:00
Janos Guljas
34edbc8868 swarm/api: remove unneeded assignment in MultiResolverOptionWithResolver 2017-12-04 22:29:37 +01:00
Janos Guljas
15ad6f27da swarm: check if "--ens-api ''" is specified in order to disable ENS 2017-12-04 22:28:11 +01:00
Janos Guljas
b33a051a48 swarm: add comment for parseFlagEnsAPI and fix a mistake in comment in code 2017-12-04 22:20:29 +01:00
Steven Roose
afb8154eab common: improve IsHexAddress and add tests (#15551)
Also unexport isHex, hasHexPrefix because IsHexAddress is the only caller.

Fixes #15550
2017-12-04 19:34:15 +01:00
Janos Guljas
7898e0d585 swarm: multiple --ens-api flags
Allow multiple --ens-api flags to be specified with value format
[tld:][contract-addr@]url.

Backward compatibility with only one --ens-api flag and --ens-addr
flag is preserved and conflict cases are handled:

 - multiple --ens-api with --ens-addr returns an error

 - single --ens-api with contract address and --ens-addr with
   different contract address returns an error

Previously implemented --ens-endpoint is removed. Its functionality
is replaced with multiple --ens-api flags.
2017-12-04 12:44:24 +01:00
ferhat elmas
1d06e41f04 p2p, swarm/network/kademlia: use IsZero to check for zero time (#15603) 2017-12-04 11:07:10 +01:00
ferhat elmas
43dd8e62fc build: enable gosimple linter (#15593) 2017-12-01 13:04:06 +01:00
Matthew Di Ferrante
80c6dfc19f crypto/bn256: fix generator on G1 (#15591)
Generator in the current lib uses -2 as the y point when doing
ScalarBaseMult, this makes it so that points/signatures generated
from libs like py_ecc don't match/validate as pretty much all
other libs (including libsnark) have (1, 2) as the standard
generator.

This does not affect consensus as the generator is never used in
the VM, points are always explicitly defined and there is not
ScalarBaseMult op - it only makes it so that doing "import
github.com/ethereum/go-ethereum/crypto/bn256" doesn't generate
bad points in userland tools.
2017-12-01 13:03:39 +01:00
Rob
d927c67f9d eth/downloader: update tests for reliability (#15337)
Updated use of Parallel and added some subtests to help isolate
them. Increased timeout in RequestHeadersByNumber so it
doesn't time out and causes other tests to break.
2017-12-01 12:54:17 +01:00
Guillaume Ballet
20fe928914 whisper: rename EnvNonce to Nonce in the v6 Envelope (#15579) 2017-12-01 12:50:19 +01:00
Lewis Marshall
54aeb8e4c0 p2p/simulations: various stability fixes (#15198)
p2p/simulations: introduce dialBan

- Refactor simulations/network connection getters to support
  avoiding simultaneous dials between two peers If two peers dial
  simultaneously, the connection will be dropped to help avoid
  that, we essentially lock the connection object with a
  timestamp which serves as a ban on dialing for a period of time
  (dialBanTimeout).

- The connection getter InitConn can be wrapped and passed to the
  nodes via adapters.NodeConfig#Reachable field and then used by
  the respective services when they initiate connections. This
  massively stablise the emerging connectivity when running with
  hundreds of nodes bootstrapping a network.

p2p: add Inbound public method to p2p.Peer

p2p/simulations: Add server id to logs to support debugging
in-memory network simulations when multiple peers are logging.

p2p: SetupConn now returns error. The dialer checks the error and
only calls resolve if the actual TCP dial fails.
2017-12-01 12:49:04 +01:00
Janos Guljas
057af8c5c8 swarm: add CLI --ens-endpoint flag (#14386)
Implement a CLI flag that can be repeated to allow multiple ENS
resolvers for different TLDs.
2017-12-01 11:25:50 +01:00
Zach
73067fd24f buld: enable goconst linter (#15566) 2017-11-30 11:22:26 +01:00
Péter Szilágyi
e37f7be97e Merge pull request #15577 from karalabe/common-hexconvert-singlebyte
common: fix hex utils to handle 1 byte address conversions
2017-11-29 11:27:24 +02:00
Péter Szilágyi
b33a5294ea common: fix hex utils to handle 1 byte address conversions 2017-11-29 02:25:32 +02:00
Felix Lange
be12392fba core/vm: track 63/64 call gas off stack (#15563)
* core/vm: track 63/64 call gas off stack

Gas calculations in gasCall* relayed the available gas for calls by
replacing it on the stack. This lead to inconsistent traces, which we
papered over by copying the pre-execution stack in trace mode.

This change relays available gas using a temporary variable, off the
stack, and allows removing the weird copy.

* core/vm: remove stackCopy

* core/vm: pop call gas into pool

* core/vm: to -> addr
2017-11-28 21:05:49 +02:00
Maximilian Meister
8f35e3086c cmd/geth: fix geth attach --datadir=... (#15517) 2017-11-28 14:00:00 +01:00
Péter Szilágyi
e323ed5a9a Merge pull request #15557 from MaximilianMeister/bootnodes-toml
cmd/utils: bootstrap nodes in config file were not respected
2017-11-28 13:34:14 +02:00
Zach
6bb61ee9ef build: improve ci.go synopsis (#15565) 2017-11-28 10:45:48 +01:00
gary rong
0f7fbb85d6 trie: make fullnode children hash calculation concurrently (#15131)
* trie: make fullnode children hash calculation concurrently

* trie: thread out only on topmost fullnode

* trie: clean up full node children hash calculation

* trie: minor code fixups
2017-11-27 13:34:17 +02:00
Maximilian Meister
62dc530773 cmd/utils: bootstrap nodes in config file were not respected
Signed-off-by: Maximilian Meister <mmeister@suse.de>
2017-11-26 12:42:51 +01:00
Paul Litvak
e4c9fd29a3 cmd/utils: disallow --lightserv in light mode (#15514)
* Disallow --lightserv in light mode

* Reformatted

* cmd/utils: reduce nesting levels a bit
2017-11-24 17:07:21 +02:00
Péter Szilágyi
de37e088f2 Merge pull request #15549 from karalabe/statedb-copy
core/state: copy trie too, not just content
2017-11-24 17:02:40 +02:00
Péter Szilágyi
f0ac925fa7 Merge pull request #15329 from holisticode/exact-match-fix
swarm/api: bug fix exact match for manifest
2017-11-24 16:23:37 +02:00
Péter Szilágyi
0981d2e566 Merge pull request #15498 from nonsense/account_cache_modtime_test_fix
accounts/keystore: change modtime for test case files to be bigger than 1sec.
2017-11-24 16:21:39 +02:00
gary rong
f14047dae5 cmd, consensus, eth: split ethash related config to it own (#15520)
* cmd, consensus, eth: split ethash related config to it own

* eth, consensus: minor polish

* eth, consenus, console: compress pow testing config field to single one

* consensus, eth: document pow mode
2017-11-24 16:10:27 +02:00
Péter Szilágyi
b0056f5bd0 Merge pull request #15552 from karalabe/javascript-tracers-nowrap
internal/ethapi: avoid recreating JavaScript tracer wrappers
2017-11-24 15:45:08 +02:00
Péter Szilágyi
5dea0f2aa4 core/state: copy trie too, not just content 2017-11-24 14:20:49 +02:00
Péter Szilágyi
989fb4472a internal/ethapi: avoid recreating JavaScript tracer wrappers 2017-11-24 13:55:12 +02:00
Ricardo Domingos
9ff9d04a69 all: fix code comment typos (#15547)
* console: fix typo in comment

* contracts/release: fix typo in comment

* core: fix typo in comment

* eth: fix typo in comment

* miner: fix typo in comment
2017-11-24 11:20:01 +02:00
Zoe Nolan
edc3e0efeb cmd/puppeth: fix typo in comment (#15539)
* cmd: fix typo in comment

* cmd/puppeth: tiny comment fixup
2017-11-24 10:58:28 +02:00
Péter Szilágyi
f9569f3cd8 Merge pull request #15390 from karalabe/puppeth-devcon3
cmd/puppeth: new version as presented at devcon3
2017-11-24 10:56:33 +02:00
Péter Szilágyi
a3a2c6b0d9 cmd/puppeth: fix typos and review suggestions 2017-11-23 14:22:59 +02:00
Péter Szilágyi
35801f938e Merge pull request #15538 from zoenolan/patch-1
build: fix typo in comment
2017-11-23 14:06:48 +02:00
Zoe Nolan
cc3ca63dbf build: fix typo in comment 2017-11-21 19:23:42 +00:00
Péter Szilágyi
049797d40a Merge pull request #15521 from rjl493456442/clean_tx_journal
les: clean up tx journal file after testing
2017-11-21 20:42:11 +02:00
rjl493456442
41ef34ae40 les: use modified default txpool config to avoid creating journal file 2017-11-21 22:13:57 +08:00
Péter Szilágyi
b169a309f9 cmd/puppeth: fix unconvert linters 2017-11-21 15:13:08 +02:00
Péter Szilágyi
7f40ae7876 cmd/puppeth: switch over to upstream alltools docker image 2017-11-21 15:09:40 +02:00
Péter Szilágyi
327dcd3622 cmd/faucet, cmd/puppeth: drop GitHub support at official request 2017-11-21 15:09:39 +02:00
Péter Szilágyi
ffc12f63ec cmd/puppeth: simplifications and pre-built docker images 2017-11-21 15:09:39 +02:00
Péter Szilágyi
80be5e5463 cmd/puppeth: store genesis locally to persist restarts 2017-11-21 15:09:38 +02:00
Péter Szilágyi
7abf968d6f cmd/puppeth: skip genesis custom extra-data 2017-11-21 15:09:37 +02:00
Péter Szilágyi
6eb38e02a8 cmd/puppeth: fix dashboard iframes, extend with new services 2017-11-21 15:09:36 +02:00
Péter Szilágyi
51a86f61be cmd/faucet: protocol relative websockets, noauth mode 2017-11-21 15:09:36 +02:00
Péter Szilágyi
b5cf603895 cmd/puppeth: add support for deploying web wallets 2017-11-21 15:09:35 +02:00
Péter Szilágyi
1e0c336d29 cmd/puppeth: etherchain light block explorer for PoW nets 2017-11-21 15:09:34 +02:00
Péter Szilágyi
9e095251b7 cmd/puppeth: mount ethash dir from the host to cache DAGs 2017-11-21 15:09:33 +02:00
Péter Szilágyi
da3b9f831e cmd/puppeth: support deploying services with forced rebuilds 2017-11-21 15:09:33 +02:00
Péter Szilágyi
7b258c9681 cmd/puppeth: concurrent server dials and health checks 2017-11-21 15:09:32 +02:00
Péter Szilágyi
8c78449a9e cmd/puppeth: reorganize stats reports to make it readable 2017-11-21 15:09:28 +02:00
Péter Szilágyi
005665867d VERSION, params: begin 1.8.0 release cycle 2017-11-21 11:59:12 +02:00
Péter Szilágyi
4bb3c89d44 params: release v1.7.3 stable 2017-11-21 11:54:19 +02:00
Martin Holst Swende
bedf6f40af cmd/geth: make geth account new faster with many keys (#15529) 2017-11-20 17:39:53 +01:00
Felix Lange
b4f2e4de8f .github: add CODEOWNERS (#15507) 2017-11-20 17:32:23 +01:00
Nick Johnson
72ed186f46 eth, internal: Implement getModifiedAccountsBy(Hash|Number) using trie diffs (#15512)
* eth, internal: Implement  using trie diffs

* eth, internal: Changes in response to review

* eth: More fixes to getModifiedAccountsBy*

* eth: minor polishes on error capitalization
2017-11-20 17:18:50 +02:00
Péter Szilágyi
7b95cca56c Merge pull request #15527 from holiman/bump_watch
accounts/keystore: Ignore initial trigger of rescan-event
2017-11-20 13:54:15 +02:00
Martin Holst Swende
e2b3a23663 accounts/keystore: Ignore initial trigger of rescan-event 2017-11-20 12:35:30 +01:00
Péter Szilágyi
0f184d3b14 Merge pull request #15526 from karalabe/accounts-new
accounts: fix two races in the account manager
2017-11-20 13:14:57 +02:00
Péter Szilágyi
6810674de9 accounts/keystore: lock file cache during scan, minor polish 2017-11-20 12:21:52 +02:00
Péter Szilágyi
8a79836044 accounts: list, then subscribe (sub requires active reader) 2017-11-20 12:20:46 +02:00
Pulyak Viktor
f5091e5711 internal/ethapi: fix js tracer to properly decode addresses (#15297)
* Add method getBalanceFromJs for work with address as bytes

* expect []byte instead of common.Address in ethapi tracer
2017-11-18 03:56:03 +02:00
Péter Szilágyi
0dbf55d478 Merge pull request #15509 from tbm/typo
Fix typo in README.md
2017-11-17 17:01:53 +02:00
Martin Michlmayr
2ab5c11261 README: fix typo 2017-11-17 14:45:09 +00:00
Péter Szilágyi
e39ca5e597 Merge pull request #15506 from tsarpaul/master
internal/ethapi: changed output in txpool.inspect
2017-11-17 15:16:49 +02:00
tsarpaul
c7b0abf86b Added output to clarify gas calculation in txpool.inspect 2017-11-17 15:07:57 +02:00
Péter Szilágyi
c8b7ea1c2e Merge pull request #15505 from karalabe/fix-rpc-pr
rpc: minor cleanups to RPC PR
2017-11-17 14:59:44 +02:00
Péter Szilágyi
3c6b9c5d72 rpc: minor cleanups to RPC PR 2017-11-17 14:25:02 +02:00
Armani Ferrante
c5b8569707 rpc: disallow PUT and DELETE on HTTP (#15501)
Fixes #15493
2017-11-17 13:07:11 +01:00
Péter Szilágyi
b0190189a3 core/vm, internal/ethapi: tracer no full storage, nicer json output (#15499)
* core/vm, internal/ethapi: tracer no full storage, nicer json output

* core/vm, internal/ethapi: omit disabled trace fields
2017-11-16 18:53:18 +02:00
Péter Szilágyi
87f5b4123c Merge pull request #15496 from karalabe/rpc-get-healthcheck
rpc: allow dumb empty requests for AWS health checks
2017-11-16 17:03:06 +02:00
Anton Evangelatov
b64525694b accounts/keystore: comments above time.Sleep 2017-11-16 15:01:02 +01:00
Anton Evangelatov
448abb61eb accounts/keystore: change modtime for test cases to be bigger than 1sec. 2017-11-16 14:17:28 +01:00
Péter Szilágyi
4013e23312 rpc: allow dumb empty requests for AWS health checks 2017-11-16 13:51:06 +02:00
jtakalai
5aa3eac22d eth/downloader: minor comments cleanup (#15495)
it's -> its

pet peeve, and I like to imagine I'm not alone.
2017-11-16 13:14:51 +02:00
Péter Szilágyi
bb57f1f1e5 Merge pull request #15489 from karalabe/bloombits-shifted-start
core/bloombits: handle non 8-bit boundary section matches
2017-11-15 14:34:53 +02:00
Péter Szilágyi
463014126f core/bloombits: handle non 8-bit boundary section matches 2017-11-15 14:10:35 +02:00
Péter Szilágyi
bce5d837b5 Merge pull request #14582 from holiman/jumpdest_improv
core/vm: improve jumpdest analysis
2017-11-15 10:52:14 +02:00
Péter Szilágyi
43c8a1914c Merge pull request #15470 from karalabe/clique-sametd-splitter
core: split same-td blocks on block height
2017-11-15 10:44:18 +02:00
Kurkó Mihály
ba62215d9e cmd, dashboard: dashboard using React, Material-UI, Recharts (#15393)
* cmd, dashboard: dashboard using React, Material-UI, Recharts

* cmd, dashboard, metrics: initial proof of concept dashboard

* dashboard: delete blobs

* dashboard: gofmt -s -w .

* dashboard: minor text and code polishes
2017-11-14 19:34:00 +02:00
gary rong
984c25ac40 accounts, internal: fail if no suitable estimated gas found (#15477)
* accounts, internal: return an error if no suitable estimated gas found

* accounts, internal: minor polishes on the gas estimator
2017-11-14 18:26:31 +02:00
Péter Szilágyi
a3128f9099 Merge pull request #15479 from guoger/patch-1
core/vm: fix typos in jump_table.go
2017-11-14 15:06:29 +02:00
Jay Guo
924098c6e5 core/vm: fix typos in jump_table.go 2017-11-14 17:57:37 +08:00
Martin Holst Swende
96ddf27a48 core/vm: copyright header on test-file 2017-11-13 22:04:53 +01:00
Péter Szilágyi
54ce3887d8 core: split same-td blocks on block height 2017-11-13 17:07:05 +02:00
Péter Szilágyi
b81a9cd829 Merge pull request #15467 from karalabe/docker-alltools
Dockerfile: support alltools image beside plain Geth
2017-11-13 14:40:37 +02:00
Péter Szilágyi
cef06358ff Dockerfile: support alltools image beside plain Geth 2017-11-13 14:30:13 +02:00
Péter Szilágyi
9b97f98334 Merge pull request #15457 from robert-zaremba/testify
vendor: add github.com/stretchr/testify test dependency
2017-11-13 14:23:38 +02:00
Péter Szilágyi
836314c055 Merge pull request #15464 from karalabe/docker-fix
dockerignore, internal/build: forward correct git folder
2017-11-12 22:56:38 +02:00
Péter Szilágyi
e401536c97 dockerignore, internal/build: forward correct git folder 2017-11-12 22:52:41 +02:00
Bo
cb8bbe7081 puppeth: handle encrypted ssh keys (closes #15442) (#15443)
* cmd/puppeth: handle encrypted ssh keys

* cmd/puppeth: fix unconvert linter error
2017-11-12 22:24:42 +02:00
Arba Sasmoyo
f47adc9ea8 .dockerignore, internal/build: Read git information directly from file (#15458)
* .dockerignore, internal/build: Read git information directly from file

This commit changes the way of retrieving git commit and branch for build
environment from running git command to reading git files directly.

This commit also adds required git files into Docker build context.

fixes: #15346

* .dockerignore: workaround for including some files in .git
2017-11-12 22:00:18 +02:00
Robert Zaremba
5d895db2fd vendor: add github.com/stretchr/testify test dependency
github.com/stretchr/testify is a useful library for doing
assertion in tests. It makes assertions in test more less verbose and
more comfortable to read and use.
2017-11-11 00:29:41 +01:00
ferhat elmas
86f6568f66 build: enable unconvert linter (#15456)
* build: enable unconvert linter

 - fixes #15453
 - update code base for failing cases

* cmd/puppeth: replace syscall.Stdin with os.Stdin.Fd() for unconvert linter
2017-11-10 19:06:45 +02:00
Benoit Verkindt
3ee86a57f3 rpc: warn on WebSocket origin mismatch (#15451)
Fixes #15373
2017-11-10 10:22:06 +01:00
Alex Beregszaszi
b31cc71ff6 contracts/chequebook: update for latest Solidity (#15425)
This changes behaviour: before if the owner/amount didn't match, it
resulted in a successful execution without doing anything; now it
results in a failed execution using the revert opcode (remainder gas
is not consumed).
2017-11-10 10:19:51 +01:00
Péter Szilágyi
febfea7af2 Merge pull request #15450 from karalabe/lint-gofmt-misspell
build: enable gofmt and misspell linters
2017-11-10 11:09:47 +02:00
Péter Szilágyi
d1eb4006e2 build: enable gofmt and misspell linters 2017-11-09 19:48:12 +02:00
Fabio Barone
03ec3fed2b swarm/api: bug fix exact match for manifest 2017-11-09 10:38:42 -05:00
Péter Szilágyi
3d88ecd61a Merge pull request #15448 from karalabe/android-build-fix
travis: bump Android NDK version and Android Go builder
2017-11-09 14:43:37 +02:00
Péter Szilágyi
09b347fec9 travis: bump Android NDK version and Android Go builder 2017-11-09 14:32:05 +02:00
Dan Melton
d7f2462e8f build: add Travis job to lint Go code #15372 (#15416)
* build: [finishes #15372] implements generalized linter and travis job

* .travis, build: minor polishes, disable deadcode
2017-11-09 12:46:03 +02:00
bas-vk
4fe30bf5ad rpc: check content-type for HTTP requests (#15220) 2017-11-09 10:54:58 +01:00
bas-vk
4732ee89cb github: add remark about general questions (#15250) 2017-11-09 10:51:14 +01:00
b00ris
7ace023981 les: fix channel assignment data race (#15441) 2017-11-09 10:43:37 +01:00
Evgeny Danilenko
0914d4e0d2 les: fix misuse of WaitGroup (#15365) 2017-11-09 10:34:35 +01:00
ferhat elmas
9619a61024 all: gofmt -w -s (#15419) 2017-11-08 11:45:52 +01:00
Eugene Valeyev
bfdc0fa362 mobile: fix FilterLogs (#15418)
All logs in the FilterLog return value would be the same object 
because the for loop captured the pointer to the iteration variable.
2017-11-06 09:46:43 -06:00
gluk256
9f7cd75682 whisper/whisperv6: initial commit (clone of v5) (#15324) 2017-11-03 21:29:49 +01:00
Jim McDonald
0131bd6ff9 core: respect price bump threshold (#15401)
* core: allow price bump at threshold

* core: test changes to allow price bump at threshold

* core: reinstate tx replacement test underneath threshold

* core: minor test failure message cleanups
2017-10-30 13:05:00 +02:00
Péter Szilágyi
dd8a62683e Merge pull request #15398 from ferhatelmas/core-swarm-typo
core, swarm: typo fixes
2017-10-30 11:08:24 +02:00
ferhat elmas
07e8c177e7 core, swarm: typo fixes 2017-10-30 01:23:23 +01:00
Felföldi Zsolt
8d434f6a6f les, core/bloombits: post-LES/2 fixes (#15391)
* les: fix topic ID

* core/bloombits: fix interface conversion
2017-10-27 17:18:53 +03:00
Péter Szilágyi
6dafec0666 Merge pull request #15389 from mcdee/rlpdump
cmd/rlpdump: allow hex input to have leading '0x'
2017-10-27 13:11:22 +03:00
Jim McDonald
3e6d7c169b cmd/rlpdump: allow hex input to have leading '0x' 2017-10-27 09:40:52 +01:00
Péter Szilágyi
0095531a58 core, eth, les: fix messy code (#15367)
* core, eth, les: fix messy code

* les: fixed tx status test and rlp encoding

* core: add a workaround for light sync
2017-10-25 12:18:44 +03:00
Felföldi Zsolt
ca376ead88 les, light: LES/2 protocol version (#14970)
This PR implements the new LES protocol version extensions:

* new and more efficient Merkle proofs reply format (when replying to
  a multiple Merkle proofs request, we just send a single set of trie
  nodes containing all necessary nodes)
* BBT (BloomBitsTrie) works similarly to the existing CHT and contains
  the bloombits search data to speed up log searches
* GetTxStatusMsg returns the inclusion position or the
  pending/queued/unknown state of a transaction referenced by hash
* an optional signature of new block data (number/hash/td) can be
  included in AnnounceMsg to provide an option for "very light
  clients" (mobile/embedded devices) to skip expensive Ethash check
  and accept multiple signatures of somewhat trusted servers (still a
  lot better than trusting a single server completely and retrieving
  everything through RPC). The new client mode is not implemented in
  this PR, just the protocol extension.
2017-10-24 15:19:09 +02:00
Péter Szilágyi
6d6a5a9337 cmd, consensus, core, miner: instatx clique for --dev (#15323)
* cmd, consensus, core, miner: instatx clique for --dev

* cmd, consensus, clique: support configurable --dev block times

* cmd, core: allow --dev to use persistent storage too
2017-10-24 13:40:42 +03:00
Anton Markelov
ea5f2da39a README: add docker RPC access docs (#15362) 2017-10-24 09:55:20 +03:00
Péter Szilágyi
479aa61f11 Merge pull request #15343 from karalabe/txpool-replacement-propagation
core: fire tx event on replace, expand tests
2017-10-20 15:21:54 +03:00
Péter Szilágyi
0af1ab0c86 core: avoid warning when loading the transaction journal 2017-10-20 14:42:20 +03:00
Péter Szilágyi
65738c1eb3 event: fix datarace between Subscribe and Send 2017-10-20 14:42:19 +03:00
Péter Szilágyi
0e7d019e0e core: fire tx event on replace, expand tests 2017-10-20 14:42:19 +03:00
Péter Szilágyi
eaa4f8a5f9 Merge pull request #15344 from karalabe/ubuntu=artful
build: start shipping Ubuntu Artful Aardvark binaries
2017-10-20 13:25:19 +03:00
Martin Holst Swende
0900aae412 cmd/evm: print stateroot in evm utility (#15341) 2017-10-20 13:22:06 +03:00
Péter Szilágyi
ba2201981a build: start shipping Ubuntu Artful Aardvark binaries 2017-10-20 12:49:32 +03:00
baizhenxuan
eea996e4e1 whisper/shhclient: fix Version return type (#15306) 2017-10-18 11:16:12 +02:00
Péter Szilágyi
2ab7fe8982 Merge pull request #15313 from karalabe/puppeth-nongithub-faucet
cmd/faucet: support twitter, google+ and facebook auth too
2017-10-17 23:20:20 +03:00
Péter Szilágyi
5d2c947060 cmd/faucet: dynamic funding progress and visual feedback 2017-10-17 14:55:21 +03:00
Sumit Sarin
e5c19b6f98 README: fix typo (#15312) 2017-10-17 13:15:42 +02:00
RJ Catalano
dec8bba9d4 accounts/abi: improve type handling, add event support (#14743) 2017-10-17 13:07:08 +02:00
Péter Szilágyi
7f7abfe4d1 cmd/faucet: proper error handling all over 2017-10-17 12:08:57 +03:00
Péter Szilágyi
0bb194c956 cmd/faucet: support twitter, google+ and facebook auth too 2017-10-16 16:57:04 +03:00
Péter Szilágyi
e9295163aa VERSION, params: start 1.7.3 release cycle 2017-10-14 16:00:46 +03:00
Péter Szilágyi
1db4ecdc0b params: bump to 1.7.2 stable 2017-10-14 15:58:53 +03:00
Péter Szilágyi
fdb3bd287e Merge pull request #15298 from karalabe/stack-then-readonly
core/vm: check opcode stack before readonly enforcement
2017-10-14 15:57:08 +03:00
Péter Szilágyi
a91e682234 core/vm: check opcode stack before readonly enforcement 2017-10-14 15:42:48 +03:00
Péter Szilágyi
41b7745529 Merge pull request #15288 from karalabe/trie-hash-benchmark
trie: make hasher benchmark meaningful post-caches
2017-10-13 15:50:05 +03:00
Péter Szilágyi
a5fcaa55ac trie: make hasher benchmark meaningful post-caches 2017-10-13 11:22:38 +03:00
Péter Szilágyi
0ed4d76c79 Merge pull request #15275 from mcdee/master
core/types: fix test for TransactionsByPriceAndNonce
2017-10-13 10:51:22 +03:00
Péter Szilágyi
4b5e797288 Merge pull request #15287 from ernestodeltoro/typo_thoretical
ethash: fix typo
2017-10-13 10:47:48 +03:00
Ernesto del Toro
2e83c82f80 ethash: fix typo 2017-10-13 01:13:52 -04:00
Yondon Fu
a5330fe0c5 accounts/abi: include fixed array size in offset for dynamic type 2017-10-12 10:58:53 -04:00
Péter Szilágyi
8d8034fe59 Merge pull request #15269 from karalabe/puppeth-dumb-ip-filtering
cmd/puppeth: use dumb textual IP filtering
2017-10-12 13:46:57 +03:00
Péter Szilágyi
fd0e7b1c67 Merge pull request #15280 from terasum/master
miner: fix typo
2017-10-12 13:46:29 +03:00
terasum
e9382c6e9f miner: fix typo 2017-10-12 10:19:23 +08:00
Jim McDonald
c599b78f62 core/types: fix test for TransactionsByPriceAndNonce 2017-10-11 11:35:44 +01:00
Péter Szilágyi
ad44475231 Merge pull request #14785 from Arachnid/downloaddb
cmd: Added support for downloading to another DB instance
2017-10-11 13:10:18 +03:00
Péter Szilágyi
35767dfd0c cmd, eth: separate out FakePeer for future reuse 2017-10-10 15:52:11 +03:00
Nick Johnson
345332906c cmd: Added support for copying data to another DB instance 2017-10-10 15:52:10 +03:00
Jia Chenhui
cefeb58598 event: fix typo (#15270) 2017-10-10 14:11:15 +02:00
Péter Szilágyi
b45cc0c9e8 cmd/puppeth: use dumb textual IP filtering 2017-10-10 12:35:09 +03:00
Péter Szilágyi
3680cd5926 params: explain EIP150Hash (#15237) 2017-10-10 10:56:33 +02:00
Péter Szilágyi
d3beff7e20 consensus/clique: add fork hash enforcement (#15236) 2017-10-10 10:54:47 +02:00
Miya Chen
40a3856af9 eth/fetcher: check the origin of filter tasks (#14975)
* eth/fetcher: check the origin of filter task

* eth/fetcher: add some details to fetcher logs
2017-10-10 11:53:05 +03:00
Darrel Herbst
89860f4197 swarm/fuse: return amount of data written if the file exists (#15261)
If the file already existed, the WriteResponse.Size was being set
as the length of the entire file, not just the amount that was
written to the existing file.

Fixes #15216
2017-10-09 12:45:30 +02:00
Martin Holst Swende
88b1db7288 accounts/keystore: scan key directory without locks held (#15171)
The accountCache contains a file cache, and remembers from
scan to scan what files were present earlier. Thus, whenever
there's a change, the scan phase only bothers processing new
and removed files.
2017-10-09 12:40:50 +02:00
Guillaume Ballet
7a045af05b whisper/whisperv5: set filter SymKeyHash on creation (#15165) 2017-10-06 16:04:21 +02:00
Guillaume Ballet
36243c7ed8 internal/web3ext: make whisper v5 methods work (#15111) 2017-10-06 15:53:29 +02:00
holisticode
1ae0411d41 swarm/api: fixed 404 handling on missing default entry (#15139) 2017-10-06 15:45:54 +02:00
Darrel Herbst
d54e3539d4 p2p/nat: delete port mapping before adding (#15222)
Fixes #1024
2017-10-06 13:39:47 +02:00
Lio李欧
5df0b240ae eth: fix typo (#15252) 2017-10-06 12:55:18 +02:00
ligi
605c2b261f mobile: fix variadic argument expansion 2017-10-05 21:08:14 +03:00
Péter Szilágyi
4bc60e3aa8 Merge pull request #15241 from karalabe/puppeth-fork-management
cmd/puppeth: support managing fork block in the chain config
2017-10-05 19:40:25 +03:00
Péter Szilágyi
eb9abbd3f2 Merge pull request #15248 from karalabe/update-liner
vendor: update liner to fix docker and mips bugs
2017-10-05 16:45:13 +03:00
Péter Szilágyi
41d361565b vendor: update liner to fix docker and mips bugs 2017-10-05 15:57:33 +03:00
Péter Szilágyi
edba5e9854 cmd/puppeth: support managing fork block in the chain config 2017-10-04 12:15:58 +03:00
Felix Lange
c0a1f1c907 params, VERSION: v1.7.2 unstable 2017-10-03 19:19:37 +02:00
Felix Lange
0510164145 params: v1.7.1 stable 2017-10-03 19:18:39 +02:00
Péter Szilágyi
629b5837e9 core: revert invalid block dedup code (#15235) 2017-10-03 18:59:53 +02:00
Péter Szilágyi
c2d93ded35 Merge pull request #15232 from karalabe/macos-usbhw-fixes
accounts/usbwallet: handle bad interface number on macOS
2017-10-03 13:14:18 +03:00
Péter Szilágyi
8d126a4981 accounts/usbwallet: handle bad interface number on macOS 2017-10-03 12:45:45 +03:00
Péter Szilágyi
f4c49bc0f0 Merge pull request #15030 from rjl493456442/expose_vm_failed
internal, accounts, eth: utilize vm failed flag to help gas estimation
2017-10-02 16:23:21 +03:00
Péter Szilágyi
d347656280 Merge pull request #15224 from karalabe/byzantium-block-numbers
cmd/puppeth, params: enable Byzantium on all networks
2017-10-02 15:40:54 +03:00
rjl493456442
94903d572b internal, accounts, eth: utilize vm failed flag to help gas estimation 2017-10-02 15:26:40 +03:00
Péter Szilágyi
f86c4177d5 Merge pull request #15042 from rjl493456442/receipt_rpc
internal/ethapi: add status code to receipt rpc return
2017-10-02 14:41:10 +03:00
Péter Szilágyi
7e9e3a134b core/types, internal: swap Receipt.Failed to Status 2017-10-02 14:04:22 +03:00
Péter Szilágyi
7514e8a24d cmd/puppeth, params: enable Byzantium on all networks 2017-10-02 13:01:40 +03:00
rjl493456442
a31835c8b4 internal/ethapi: add status code to receipt rpc return 2017-10-02 11:42:53 +03:00
Felix Lange
d78ad226c2 ethclient, mobile: add TransactionSender (#15127)
* core/types: make Signer derive address instead of public key

There are two reasons to do this now: The upcoming ethclient signer
doesn't know the public key, just the address. EIP 208 will introduce a
new signer which derives the 'entry point' address for transactions with
zero signature. The entry point has no public key.

Other changes to the interface ease the path make to moving signature
crypto out of core/types later.

* ethclient, mobile: add TransactionSender

The new method can get the right signer without any crypto, and without
knowledge of the signature scheme that was used when the transaction was
included.
2017-10-01 11:03:28 +02:00
Martin Holst Swende
a660685746 tests: add ethash difficulty tests (#15191) 2017-09-27 15:30:41 +02:00
Péter Szilágyi
2ab2a9f131 core/bloombits, eth/filters: handle null topics (#15195)
When implementing the new bloombits based filter, I've accidentally broke null
topics by removing the special casing of common.Hash{} filter rules, which
acted as the wildcard topic until now.

This PR fixes the regression, but instead of using the magic hash
common.Hash{} as the null wildcard, the PR reworks the code to handle nil
topics during parsing, converting a JSON null into nil []common.Hash topic.
2017-09-27 12:14:52 +02:00
Péter Szilágyi
860e697b00 Merge pull request #15208 from ayeowch/fix-typo
cmd/geth: fix --password typo
2017-09-27 11:01:38 +03:00
ayeowch
f3c9585f2e cmd/geth: fix --password typo 2017-09-27 10:28:26 +10:00
Péter Szilágyi
229bf51f0d Merge pull request #15181 from fjl/state-revert-log-index
core/state: revert log index when removing logs
2017-09-26 17:11:46 +03:00
Péter Szilágyi
2ee885958b p2p: snappy encoding for devp2p (version bump to 5) (#15106)
* p2p: snappy encoding for devp2p (version bump to 5)

* p2p: remove lazy decompression, enforce 16MB limit
2017-09-26 16:54:49 +03:00
slumber1122
2b4a5f2677 internal/ethapi: remove code duplication around tx sending (#15158) 2017-09-25 10:38:42 +02:00
Derek Chiang
d6a6180366 contracts/chequebook: fix two contract issues (#15086)
This patch fixes the following issues:

* The contract executes send() when it does not have enough balance.
* The contract always sends a total amount of zero.
2017-09-25 10:36:13 +02:00
Lewis Marshall
9feec51e2d p2p: add network simulation framework (#14982)
This commit introduces a network simulation framework which
can be used to run simulated networks of devp2p nodes. The
intention is to use this for testing protocols, performing
benchmarks and visualising emergent network behaviour.
2017-09-25 10:08:07 +02:00
cdetrio
673007d7ae core/vm: standard vm traces (#15035) 2017-09-22 10:22:56 +02:00
Zahoor Mohamed
d558a595ad swarm/storage: pyramid chunker re-write (#14382) 2017-09-21 22:22:51 +02:00
Felix Lange
a0d783094e core/state: revert log index when removing logs 2017-09-21 20:46:21 +02:00
Ernesto del Toro
3c8656347f eth, internal/ethapi: fix spelling of 'Ethereum' (#15164) 2017-09-20 11:31:31 +02:00
gary rong
b9ff44bd64 params: rename EIP150 gas table (#15167) 2017-09-20 11:27:00 +02:00
Mark
cb5235eb07 miner: make starting of CPU agent more reliable (#15148) 2017-09-19 13:28:15 +02:00
Paul Litvak
a92d8a2654 trie: fix typo (#15152) 2017-09-18 23:07:19 +02:00
Davor Kapsa
dc17fa6b18 travis.yml: update go versions (#15154) 2017-09-18 23:07:02 +02:00
Dave Appleton
019dca9ba2 accounts/abi/backends: add AdjustTime (#15077) 2017-09-15 15:20:29 +02:00
Kyuntae Ethan Kim
c197d805f7 ethereum: fix typos in interfaces.go (#15149) 2017-09-15 11:30:17 +02:00
Péter Szilágyi
5705ad004e containers/docker: bump docker images to 1.7 release branch 2017-09-14 14:01:44 +03:00
Péter Szilágyi
a989cf5bad VERSION, params: begin 1.7.1 release cycle 2017-09-14 14:01:31 +03:00
Péter Szilágyi
6c6c7b2af3 params: release Geth 1.7.0 - Megara 2017-09-14 13:55:42 +03:00
Péter Szilágyi
5c93462b5e Merge pull request #15147 from karalabe/enable-byzantium-ropsten
params: enable Byzantium on Ropsten/tests, fix failures
2017-09-14 11:28:54 +03:00
Péter Szilágyi
701d60c889 params: enable Byzantium on Ropsten/tests, fix failures 2017-09-14 10:59:05 +03:00
Martin Holst Swende
9be07de539 params: Updated finalized gascosts for ECMUL/MODEXP (#15135)
* params: Updated finalized gascosts for ECMUL/MODEXP

* core,tests: Updates pending new tests

* tests: Updated with new tests

* core: revert state transition bugfix

* tests: Add expected failures due to  #15119
2017-09-14 10:35:54 +03:00
Péter Szilágyi
885c13c2c9 Merge pull request #15146 from karalabe/byzantium-rebrand
consensus, core, params: rebrand Metro to Byzantium
2017-09-14 10:29:08 +03:00
Péter Szilágyi
5bbd7fb390 consensus, core, params: rebrand Metro to Byzantium 2017-09-14 10:10:46 +03:00
Péter Szilágyi
79b11121a7 Merge pull request #15141 from karalabe/rinkeby-infura-bootnode
params: add Infura bootnode to Rinkeby
2017-09-13 12:48:00 +03:00
Péter Szilágyi
72af509abe params: add Infura bootnode to Rinkeby 2017-09-13 11:25:50 +03:00
Péter Szilágyi
382c9266e6 Merge pull request #15138 from karalabe/statesync-peer-drops
eth/downloader: track peer drops and deassign state sync tasks
2017-09-12 15:33:32 +03:00
Péter Szilágyi
f46adfac28 eth/downloader: track peer drops and deassign state sync tasks 2017-09-12 15:13:14 +03:00
Péter Szilágyi
514b1587db Merge pull request #15137 from karalabe/puppeth-keywords
cmd/puppeth: reserve "yournode" as a non-allowed ethstats user
2017-09-12 11:50:53 +03:00
Péter Szilágyi
66a7ef57e6 cmd/puppeth: reserve "yournode" as a non-allowed ethstats user 2017-09-12 11:35:35 +03:00
Péter Szilágyi
ecca2c3c1b Merge pull request #15129 from zsfelfoldi/cht1040
light: new CHTs for mainnet and ropsten
2017-09-12 10:59:01 +03:00
Zsolt Felfoldi
7a7f6a4f29 light: new CHTs for mainnet and ropsten 2017-09-11 23:36:16 +02:00
Péter Szilágyi
c8e70186a6 Merge pull request #14973 from rjl493456442/fix_downloader
eth/downloader: exit loop when there is no more available task
2017-09-11 14:02:02 +03:00
Péter Szilágyi
794741b8b2 Merge pull request #15124 from fjl/debug-gcpercent
internal/debug: add debug_setGCPercent
2017-09-11 13:34:34 +03:00
Felix Lange
48705f8aea internal/debug: add debug_setGCPercent 2017-09-11 12:29:47 +02:00
Péter Szilágyi
10b3f97c9d core: only fire one chain head per batch (#15123)
* core: only fire one chain head per batch

* miner: announce chan events synchronously
2017-09-11 13:13:05 +03:00
Felix Lange
5596b664c4 internal/debug: add debug_freeOSMemory (#15122) 2017-09-11 09:33:18 +02:00
Felix Lange
42a5b54bf5 core/vm: improve bitvec comments 2017-09-10 21:04:36 +02:00
Felix Lange
10181b57a9 core, eth/downloader: commit block data using batches (#15115)
* ethdb: add Putter interface and Has method

* ethdb: improve docs and add IdealBatchSize

* ethdb: remove memory batch lock

Batches are not safe for concurrent use.

* core: use ethdb.Putter for Write* functions

This covers the easy cases.

* core/state: simplify StateSync

* trie: optimize local node check

* ethdb: add ValueSize to Batch

* core: optimize HasHeader check

This avoids one random database read get the block number. For many uses
of HasHeader, the expectation is that it's actually there. Using Has
avoids a load + decode of the value.

* core: write fast sync block data in batches

Collect writes into batches up to the ideal size instead of issuing many
small, concurrent writes.

* eth/downloader: commit larger state batches

Collect nodes into a batch up to the ideal size instead of committing
whenever a node is received.

* core: optimize HasBlock check

This avoids a random database read to get the number.

* core: use numberCache in HasHeader

numberCache has higher capacity, increasing the odds of finding the
header without a database lookup.

* core: write imported block data using a batch

Restore batch writes of state and add blocks, tx entries, receipts to
the same batch. The change also simplifies the miner.

This commit also removes posting of logs when a forked block is imported.

* core: fix DB write error handling

* ethdb: use RLock for Has

* core: fix HasBlock comment
2017-09-09 19:03:07 +03:00
holisticode
ac193e36ce swarm/api/http: add error pages (#14967) 2017-09-08 20:29:09 +02:00
Martin Holst Swende
d6681ed360 core/vm: Rename + updated doc on jumpdest analysis 2017-09-08 12:47:44 +02:00
nkbai
5ba9225fe3 accounts/abi/bind: pass non-empty directory when calling goimports (#15070) 2017-09-07 23:34:45 +02:00
Martin Holst Swende
fc87bc5f52 common: improve documentation of Hash.SetBytes (#15062)
Fixes #15004
2017-09-07 23:32:59 +02:00
Mark
c1740e4540 core/types, miner: avoid tx sender miscaching (#14773) 2017-09-07 23:22:27 +02:00
Benoit Verkindt
e3db1236de contracts/chequebook: fix race in test (#15058) 2017-09-07 23:14:47 +02:00
Fiisio
02b4d074f6 core/asm: use ContainsRune instead of IndexRune (#15098) 2017-09-07 23:11:48 +02:00
Fiisio
2dcb22afec swarm/fuse: use Equal instead of Compare (#15097) 2017-09-07 23:10:51 +02:00
Pawan Singh Pal
69c8be7c86 core: delete dao.go (#15113)
- dao.go is already present in consensus/misc
- core/dao.go is not used anywhere in the codebase
2017-09-07 23:08:06 +02:00
Péter Szilágyi
55e5926f34 Merge pull request #15103 from karalabe/disable-fastsync-postpivot
eth: disable fast sync after pivot is committed
2017-09-07 19:29:45 +03:00
Péter Szilágyi
f30179d62e eth: disable fast sync after pivot is committed 2017-09-06 15:02:44 +03:00
Péter Szilágyi
c4d21bc8e5 Merge pull request #14631 from zsfelfoldi/bloombits2
core/bloombits, eth/filter: transformed bloom bitmap based log search
2017-09-06 13:00:35 +03:00
Péter Szilágyi
160add8570 Merge pull request #15095 from karalabe/txpool-avoid-deep-reorg
core: use blocks and avoid deep reorgs in txpool
2017-09-06 12:01:07 +03:00
Péter Szilágyi
564c8f3ae6 core/bloombits: drop nil-matcher special case 2017-09-06 11:14:22 +03:00
Zsolt Felfoldi
451ffdb62b core/bloombits: use general filters instead of addresses and topics 2017-09-06 11:14:21 +03:00
Zsolt Felfoldi
6ff2c02991 core/bloombits: AddBloom index parameter and fixes variable names 2017-09-06 11:14:20 +03:00
Péter Szilágyi
f585f9eee8 core, eth: clean up bloom filtering, add some tests 2017-09-06 11:14:19 +03:00
Zsolt Felfoldi
4ea4d2dc34 core, eth: add bloombit indexer, filter based on it 2017-09-06 11:13:13 +03:00
Péter Szilágyi
1e67378df8 Merge pull request #15094 from karalabe/eth-auto-maxpeers
eth: use maxpeers from p2p layer instead of extra config
2017-09-06 10:38:37 +03:00
Péter Szilágyi
cc313e78b7 core: use blocks and avoid deep reorgs in txpool 2017-09-05 19:50:29 +03:00
Péter Szilágyi
b0ca1b67ce eth: use maxpeers from p2p layer instead of extra config 2017-09-05 19:18:28 +03:00
Nick Johnson
03d00361f5 Merge pull request #15092 from karalabe/puppeth-main-docker-images
Dockerfile, cmd/puppeth: fix missing SSL certificates, use main image in puppeth
2017-09-05 14:24:09 +01:00
Péter Szilágyi
f90a193f92 cmd/puppeth: switch node containers to main ones 2017-09-05 16:09:41 +03:00
Péter Szilágyi
8e14bb1448 Dockerfile: fix missing SSL certificates 2017-09-05 16:06:04 +03:00
Péter Szilágyi
cd6c861dc5 vendor: pull in latest changes for goleveldb (#15090) 2017-09-05 15:04:32 +02:00
Péter Szilágyi
c91f7beb53 Merge pull request #15085 from karalabe/txpool-immutable
core: make txpool operate on immutable state
2017-09-05 13:39:18 +03:00
Viktor Trón
2bacf36d80 bmt: Binary Merkle Tree Hash (#14334)
bmt is a new package that provides hashers for binary merkle tree hashes on
size-limited chunks. the main motivation is that using BMT hash as the chunk
hash of the swarm hash offers logsize inclusion proofs for arbitrary files on a
32-byte resolution completely viable to use in challenges on the blockchain.
2017-09-05 12:38:36 +02:00
Péter Szilágyi
32d8d42274 Merge pull request #15089 from karalabe/docker-multistage
Dockerfile: multi-stage builds, Go 1.9
2017-09-05 13:36:20 +03:00
Péter Szilágyi
da7d57e07c core: make txpool operate on immutable state 2017-09-05 13:34:41 +03:00
Martin Holst Swende
8cab3ab435 cmd/evm: adds ability to run individual state test file (#14998)
* cmd/evm: adds ability to run individual state test file

* cmd/evm: Fix statetest runner to be more json friendly

* cmd/evm, tests: minor polishes, dump state on fail
2017-09-05 12:24:26 +03:00
Péter Szilágyi
8f567dc8a2 Dockerfile: multi-stage builds, Go 1.9 2017-09-05 12:16:59 +03:00
Péter Szilágyi
504278e839 build: bump PPA builders to Go 1.9 (#15083) 2017-09-05 10:16:46 +02:00
Martin Holst Swende
e7408b5552 core/vm: Make MaxCodesize non-retroactive (#15072)
* core/vm: Make max_codesize only applicable post Spurious Dragon/158/155/161/170

* tests: Remove expected failure
2017-09-04 12:53:25 +03:00
Martin Holst Swende
1901521ed0 core: Fix flaw where underpriced locals were removed (#15081)
* core: Fix flaw where underpriced locals were removed

* core: minor code cleanups for tx pool tests
2017-09-04 12:48:36 +03:00
Martin Holst Swende
23b51a68cb core/vm: avoid state lookup during gas calc for call (#15061) 2017-09-04 10:56:45 +02:00
Martin Holst Swende
dc92779c0a p2p: change ping ticker to timer (#15071)
Using a Timer over Ticker seems to be a lot better, though I cannot fully
account for why that it behaves so (since Ticker should be more bursty, but not
necessarily more active over time, but that may depend on how long window it
uses to decide on when to tick next)
2017-09-04 09:24:52 +02:00
Péter Szilágyi
d70536b5d4 Merge pull request #15047 from holiman/ecmul_benchmarks
core/vm: more benchmarks
2017-08-28 17:25:36 +03:00
Martin Holst Swende
07635e43e2 core/vm: renamed struct member + go fmt 2017-08-28 13:33:24 +02:00
Martin Holst Swende
64a3a3d23c core/vm: Fix testcase input for ecmul 2017-08-28 13:30:26 +02:00
Péter Szilágyi
777540628e Merge pull request #15054 from karalabe/go-1.9
travis, appveyor: bump Go to 1.9 stable
2017-08-28 13:19:03 +03:00
Péter Szilágyi
a4df80f47f travis, appveyor: bump Go to 1.9 stable 2017-08-28 11:15:29 +03:00
Martin Holst Swende
bc2a5578c0 core/vm: more benchmarks 2017-08-27 14:00:32 +02:00
Oli Bye
ebf41d16a0 cmd/geth: fix --nousb typo (#15040) 2017-08-25 16:54:36 +03:00
Péter Szilágyi
9d0c51fb0f Merge pull request #15039 from karalabe/metropolis-contract-clash
core, tests: implement Metropolis EIP 684
2017-08-25 16:03:39 +03:00
Péter Szilágyi
08f27428b4 core, tests: implement Metropolis EIP 684 2017-08-25 13:00:27 +03:00
Péter Szilágyi
27a5622e99 Merge pull request #15028 from karalabe/metropolis-iceage
consensus, core, tests: implement Metropolis EIP 649
2017-08-25 11:00:51 +03:00
Péter Szilágyi
8596fc5974 Merge pull request #15033 from fjl/core-receipt-status-bytes
core/types: encode receipt status in PostState field
2017-08-25 10:31:44 +03:00
Felix Lange
ad16aeb0a2 core/types: encode receipt status in PostState field
This fixes a regression where the new Failed field in ReceiptForStorage
rejected previously stored receipts. Fix it by removing the new field
and store status in the PostState field. This also removes massive RLP
hackery around the status field.
2017-08-24 23:51:50 +02:00
Péter Szilágyi
b872961ec8 consensus, core, tests: implement Metropolis EIP 649 2017-08-24 17:16:39 +03:00
Felix Lange
54b1de67e2 core/vm: make jumpdest code nicer 2017-08-24 13:09:53 +02:00
nkbai
68955ed2eb core/types: fix create indicator in Transaction.String (#15025) 2017-08-24 12:48:13 +02:00
Péter Szilágyi
ff9a868232 core/state: revert metro suicide map addition (#15024) 2017-08-24 12:42:00 +02:00
Péter Szilágyi
20b818d206 Merge pull request #15029 from karalabe/rlp-raw-decode
rlp: fix decoding long strings into RawValue types
2017-08-24 13:32:45 +03:00
Péter Szilágyi
63246e2542 rlp: fix decoding long strings into RawValue types 2017-08-24 13:10:50 +03:00
Péter Szilágyi
3c48a25762 Merge pull request #15014 from rjl493456442/metropolis-eip658
core: add status as a consensus field in receipt
2017-08-23 14:39:37 +03:00
Martin Holst Swende
286ec5df40 cmd/evm, core/vm, internal/ethapi: Show error when exiting (#14985)
* cmd/evm, core/vm, internal/ethapi: Add 'err' to tracer interface CaptureEnd

* cmd/evm: fix nullpointer when there is no error
2017-08-23 14:37:18 +03:00
Péter Szilágyi
4ee92f2d19 core/types: reject Metro receipts with > 0x01 status bytes 2017-08-23 13:57:15 +03:00
Péter Szilágyi
f7e39a7724 Merge pull request #15000 from fjl/node-flock
node: fix instance dir locking and improve error message
2017-08-23 13:36:11 +03:00
Péter Szilágyi
79cdbcfe64 Merge pull request #15018 from Bo-Ye/master
metrics: change MetricsEnabledFlag to be const
2017-08-23 13:22:46 +03:00
Péter Szilágyi
79bf69b556 tests: pull in new test suite, enable most block tests 2017-08-22 18:35:18 +03:00
rjl493456442
28aea46ac0 core: implement Metropolis EIP 658, receipt status byte 2017-08-22 18:35:17 +03:00
Péter Szilágyi
fc5f8a3dda Merge pull request #15022 from karalabe/enable-byzantium-state-tests
tests: enable Byzantium state tests for CI
2017-08-22 15:06:02 +03:00
Péter Szilágyi
3cc476c8ab tests: enable Byzantium state tests for CI 2017-08-22 14:04:44 +03:00
Ti Zhou
2fd5ba6bd4 core/vm: fix typo in method documentation (#15019)
Signed-off-by: Ti Zhou <tizhou1986@gmail.com>
2017-08-22 12:43:36 +03:00
Bo Ye
b4b27ebaea metrics: change MetricsEnabledFlag to be const 2017-08-22 18:35:09 +12:00
Péter Szilágyi
8c037dc487 Merge pull request #15017 from karalabe/usbhid-macos-thread-fix
vendor: update USB HID lib (fix macOS crash)
2017-08-21 14:32:47 +03:00
Péter Szilágyi
3e14837c1c vendor: update USB HID lib (fix macOS crash) 2017-08-21 13:45:50 +03:00
George Angel
58f7f977e7 Dockerfile: use alpine:3.6, clean up apk incovation (#15006) 2017-08-21 12:26:42 +02:00
Péter Szilágyi
afdfdebd87 Merge pull request #14983 from karalabe/metropolis-revert
core/vm: implement REVERT metropolis opcode
2017-08-21 12:23:03 +03:00
Noman
e311bb520a whisper: Fix spelling and grammar in error (#15009)
* whisper: Fix spelling and grammar in error

* whisper: Fix grammar in comments
2017-08-21 12:22:00 +03:00
Péter Szilágyi
1ab3e30698 Merge pull request #15016 from gurrpi/patch-1
README: add missing full stop
2017-08-21 11:04:07 +03:00
gurrpi
314246da78 Adding period at end of sentence
missing period at line 119
2017-08-21 15:08:57 +09:00
Miya Chen
bf1e263128 core, light: send chain events using event.Feed (#14865) 2017-08-18 12:58:36 +02:00
Felix Lange
7e57fee355 node: fix instance dir locking and improve error message
The lock file was ineffective because opening leveldb storage in
read-only mode doesn't really take the lock. Fix it by including a
dedicated flock library (which is actually split out of goleveldb).
2017-08-18 12:14:00 +02:00
Péter Szilágyi
a4da8416ee Merge pull request #14996 from markya0616/send_not_announce
eth: send but not announce block to peers if propagate is true
2017-08-18 12:47:33 +03:00
Péter Szilágyi
998abb9107 Merge pull request #14999 from karalabe/puppeth-ethstats-blacklist
cmd/puppeth: support blacklisting malicious IPs on ethstats
2017-08-18 12:39:48 +03:00
Péter Szilágyi
059c767adf cmd/puppeth: support blacklisting malicious IPs on ethstats 2017-08-18 11:23:56 +03:00
mark.lin
d4f11d9b4f eth: send but not announce block to peers if propagate is true 2017-08-18 13:52:16 +08:00
Péter Szilágyi
104375f398 Merge pull request #14993 from karalabe/bn256-precompile-fixes
core/vm, crypto/bn256: fix bn256 use and pairing corner case
2017-08-17 17:46:45 +03:00
Péter Szilágyi
1bbd400899 tests: skip the bad tests from colliding account touches 2017-08-17 16:50:36 +03:00
Péter Szilágyi
f9fb70d2ee core/vm: rework reversion to work on a higher level 2017-08-17 16:50:35 +03:00
Péter Szilágyi
1335a6cc8c core/vm, crypto/bn256: fix bn256 use and pairing corner case 2017-08-17 16:46:46 +03:00
Jeffrey Wilcke
b70a73cd3e core/vm: implement REVERT metropolis opcode 2017-08-16 15:32:59 +03:00
Péter Szilágyi
0b978f91b6 Merge pull request #14981 from karalabe/metropolis-returndata
core/vm: implement RETURNDATA metropolis opcodes
2017-08-16 15:19:33 +03:00
Péter Szilágyi
64d199edf2 tests: pull in latest tests from upstream 2017-08-16 13:43:15 +03:00
Péter Szilágyi
4e0fea4d30 core/vm: polish RETURNDATA, add missing returns to CALL* 2017-08-16 13:43:14 +03:00
Jeffrey Wilcke
9bd6068fef core/vm: implement RETURNDATA metropolis opcodes 2017-08-16 13:43:08 +03:00
Péter Szilágyi
76069eef38 Merge pull request #14978 from karalabe/metropolis-staticcall
core/vm: implement metropolis static call opcode
2017-08-16 12:39:31 +03:00
Péter Szilágyi
3df7142b3e core/vm: minor polishes, fix STATICCALL for precompiles
* Fix STATICCALL so it is able to call precompiles too
 * Fix write detection to use the correct value argument of CALL
 * Fix write protection to ignore the value in CALLCODE
2017-08-15 14:40:12 +03:00
Jeffrey Wilcke
3d123bcde6 core/vm: implement metropolis static call opcode 2017-08-15 13:03:49 +03:00
Martin Holst Swende
3040243042 cmd/evm: add --receiver, support code from stdin (#14873) 2017-08-15 11:31:36 +02:00
Péter Szilágyi
9facf6423d Merge pull request #14959 from karalabe/metropolis-precompiles
core/vm: metropolis precompiles
2017-08-15 10:31:29 +03:00
Péter Szilágyi
2403656373 Merge pull request #14951 from egonelbre/megacheck_swarm
swarm: fix megacheck warnings
2017-08-14 19:44:17 +03:00
Péter Szilágyi
ef0edc6e32 Merge pull request #14885 from karalabe/trezor-boom
accounts, console, internal: support trezor hardware wallet
2017-08-14 18:52:40 +03:00
Egon Elbre
133de3d806 swarm: fix megacheck warnings 2017-08-14 18:12:37 +03:00
Péter Szilágyi
f8d8b56b28 core/vm: optimize copy-less data retrievals 2017-08-14 17:08:49 +03:00
Martin Holst Swende
d8aaa3a215 core/vm: benchmarking of metro precompiles 2017-08-14 15:37:09 +03:00
Péter Szilágyi
6131dd55c5 core/vm: polish precompile contract code, add tests and benches
* Update modexp gas calculation to new version
 * Fix modexp modulo 0 special case to return zero
2017-08-14 15:27:44 +03:00
Péter Szilágyi
02656f9f61 console: use keypad based pinpad (Trezor request) 2017-08-14 12:21:40 +03:00
Martin Holst Swende
967e097faa core/vm: Address review concerns 2017-08-14 10:57:54 +02:00
rjl493456442
02aa86e659 eth/downloader: exit loop when there is no more available task 2017-08-14 13:51:37 +08:00
Jeffrey Wilcke
7bbdf3e268 core: add Metropolis pre-compiles (EIP 197, 198 and 213) 2017-08-11 15:24:54 +03:00
Péter Szilágyi
6ca59d98f8 Merge pull request #14964 from fjl/tests-update-2
tests: update tests, use blockchain test "network" field
2017-08-11 15:23:22 +03:00
Joel Burget
833eeb9f23 core/vm/runtime: remove unused state parameter to NewEnv (#14953)
* core: Remove unused `state` parameter to `NewEnv`.

`cfg.State` is used instead.

* core/vm/runtime: remove unused import
2017-08-11 14:29:32 +03:00
Maximilian Meister
2b422b1a47 cmd/geth, cmd/swarm: sort commands and flags by name (#3462) 2017-08-11 13:29:05 +02:00
gary rong
73c5aba21f ethdb: return copied value from MemDatabase.Get (#14958) 2017-08-11 12:41:49 +02:00
Felix Lange
6a56b15019 tests: update tests, use blockchain test "network" field
Blockchain tests now include the "network" which determines the chain
config to use. Remove config matching based on test name and share the
name-to-config index with state tests.

Byzantium/Constantinople tests are still skipped because most of them
fail anyway.
2017-08-11 12:34:03 +02:00
Péter Szilágyi
5d9ac49c7e accounts: refactor API for generalized USB wallets 2017-08-09 13:26:07 +03:00
Péter Szilágyi
db568a61e2 accounts, console, internal: support trezor hardware wallet 2017-08-09 11:30:17 +03:00
Ivan Daniluk
17ce0a37de eth/downloader: fix race in downloadTesterPeer (#14942)
* eth/downloader: fix race in downloadTesterPeer

Signed-off-by: Ivan Daniluk <ivan.daniluk@gmail.com>

* eth/downloader: minor datarace fix cleanup
2017-08-08 20:10:09 +03:00
Egon Elbre
26b2d6e1aa contracts: fix megacheck errors (#14916)
* contracts: fix megacheck errors

* contracts: drop useless sleep, lets see what breaks
2017-08-08 19:41:35 +03:00
Felföldi Zsolt
fff6e03a79 les: fix megacheck warnings (#14941)
* les: fix megacheck warnings

* les: fixed testGetProofs
2017-08-08 19:31:08 +03:00
Egon Elbre
d375193797 whisper: fix megacheck warnings (#14925)
* whisper: fix megacheck warnings

* whisper/whisperv5: regenerate json codec to fix unused override type
2017-08-08 14:48:06 +03:00
Felix Lange
374c49e0ac Merge pull request #14522 from ethereum/go-ethereum/chainproc2 2017-08-08 13:37:59 +02:00
Egon Elbre
10ce8b0e3c crypto: fix megacheck warnings (#14917)
* crypto: fix megacheck warnings

* crypto/ecies: remove ASN.1 support
2017-08-08 13:58:22 +03:00
Péter Szilágyi
9a7e99f75d Merge pull request #14940 from karalabe/txpool-races
core: fix txpool journal and test races
2017-08-08 13:20:36 +03:00
Egon Elbre
6f8c7b0def ethdb: add basic and parallel sanity tests (#14938)
* ethdb: add basic sanity test

* ethdb: test MemDatabase

* ethdb: add parallel tests
2017-08-08 12:32:10 +03:00
Péter Szilágyi
1c45f2f42e core: fix txpool journal and test races 2017-08-08 12:22:01 +03:00
Egon Elbre
e063d538b8 rpc: fix megacheck warnings 2017-08-08 11:08:37 +02:00
Péter Szilágyi
43437806fb Merge pull request #14933 from egonelbre/megacheck_eth
eth: fix megacheck warnings
2017-08-08 09:59:52 +03:00
Egon Elbre
8f06b7980d eth: fix megacheck warnings 2017-08-07 19:54:20 +03:00
Egon Elbre
971079822e light: fix megacheck warnings (#14920) 2017-08-07 17:25:18 +02:00
Egon Elbre
f42bd73ce5 internal: fix megacheck warnings (#14919) 2017-08-07 17:14:40 +02:00
Péter Szilágyi
f5925b0459 Merge pull request #14928 from fjl/build-goroot-explain
internal/build: add GoTool and document why it uses GOROOT
2017-08-07 17:47:58 +03:00
Péter Szilágyi
8edaaa227d core: polish chain indexer a bit 2017-08-07 17:38:33 +03:00
Zsolt Felfoldi
bd74882d83 core: implement ChainIndexer 2017-08-07 17:37:08 +03:00
Péter Szilágyi
67439c1dba Merge pull request #14927 from karalabe/blockchain-test-cleanups
core: fix blockchain goroutine leaks in tests
2017-08-07 17:21:29 +03:00
Felix Lange
f59a49d591 internal/build: add GoTool and document why it uses GOROOT 2017-08-07 16:08:50 +02:00
Péter Szilágyi
2b50367fe9 core: fix blockchain goroutine leaks in tests 2017-08-07 16:00:47 +03:00
Péter Szilágyi
46cf0a616b Merge pull request #14914 from egonelbre/megacheck_consensus
consensus: fix megacheck warnings
2017-08-07 14:35:45 +03:00
Egon Elbre
85454e7678 cmd: fix megacheck warnings (#14912)
* cmd: fix megacheck warnings

* cmd: revert time.Until changes, keep readFloat
2017-08-07 14:34:21 +03:00
Egon Elbre
80de4dc72c consensus: revert time.Until change 2017-08-07 14:32:03 +03:00
Péter Szilágyi
8c2cf3c66c Merge pull request #14922 from egonelbre/megacheck_miner
miner: fix megacheck warnings
2017-08-07 14:31:41 +03:00
Péter Szilágyi
37e9fcacca Merge pull request #14923 from egonelbre/megacheck_node
node: fix megacheck warnings
2017-08-07 14:28:10 +03:00
Péter Szilágyi
b36f54c684 Merge pull request #14918 from egonelbre/megacheck_ethstats
ethstats: fix megacheck warnings
2017-08-07 14:25:08 +03:00
Péter Szilágyi
3991745c5f Merge pull request #14921 from egonelbre/megacheck_log
log: fix megacheck warnings
2017-08-07 14:24:22 +03:00
Péter Szilágyi
6dd2803b8e Merge pull request #14915 from egonelbre/megacheck_console
console: fix megacheck warnings
2017-08-07 14:21:21 +03:00
Péter Szilágyi
fc0c6c175c Merge pull request #14913 from egonelbre/megacheck_common
common: fix megacheck warnings
2017-08-07 14:16:55 +03:00
Egon Elbre
7c74e166b0 accounts: fix megacheck warnings (#14903)
* accounts: fix megacheck warnings

* accounts: don't modify abi in favor of full cleanup
2017-08-07 14:11:15 +03:00
Péter Szilágyi
f7848c2aa5 Merge pull request #14911 from karalabe/txpool-flaky-test
core: bump timeout test to avoid flakyness on overloaded ci
2017-08-07 14:09:35 +03:00
Egon Elbre
19866075ac node: fix megacheck warnings 2017-08-07 13:43:08 +03:00
Egon Elbre
faafeef79e miner: fix megacheck warnings 2017-08-07 13:41:22 +03:00
Egon Elbre
cd82b89fde log: fix megacheck warnings 2017-08-07 13:40:05 +03:00
Egon Elbre
3780d0b6f7 ethstats: fix megacheck warnings 2017-08-07 13:32:19 +03:00
Egon Elbre
ff89a3ddce console: fix megacheck warnings 2017-08-07 13:19:44 +03:00
Egon Elbre
aee70ae30b consensus: fix megacheck warnings 2017-08-07 13:18:08 +03:00
Egon Elbre
392151e251 common: fix megacheck warnings 2017-08-07 13:16:56 +03:00
Péter Szilágyi
5b742fb82b core: bump timeout test to avoid flakyness on overloaded ci 2017-08-07 12:53:32 +03:00
Péter Szilágyi
b159cdd8dd Merge pull request #14910 from karalabe/drop-yakkety-support
build: drop yakkety builds (launchpad end of life)
2017-08-07 12:42:30 +03:00
Péter Szilágyi
524ca544b2 build: drop yakkety builds (launchpad end of life) 2017-08-07 11:12:44 +03:00
Péter Szilágyi
1059927f9c Merge pull request #14905 from armellini13/patch-1
node: fix doc typo
2017-08-07 09:51:00 +02:00
Agustin Armellini Fischer
fca6e515d6 node: fix doc typo 2017-08-06 00:32:17 +02:00
Péter Szilágyi
ca436f4b90 Merge pull request #14897 from karalabe/cardinal-sin
cmd/puppeth: remove wrapping loop in single reads
2017-08-05 00:34:05 +02:00
Péter Szilágyi
350bb6d9ca Merge pull request #14898 from detailyang/patch-1
Makefile: call shell function to get pwd
2017-08-04 18:23:15 +02:00
detailyang
5e805aa865 Makefile: call shell function to get pwd 2017-08-04 23:54:30 +08:00
Péter Szilágyi
455fcc8309 cmd/puppeth: remove wrapping loop in single reads 2017-08-04 17:00:22 +02:00
evgk
0cc9b8791e core/vm: fix typo in comment (#14894) 2017-08-04 01:31:18 +02:00
Péter Szilágyi
8b84bd283f Merge pull request #14889 from karalabe/ethash-cache-on-import
cmd: add makecache cmd, use caches during import cmd
2017-08-03 18:40:21 +02:00
Péter Szilágyi
4a260dc1f2 cmd: add makecache cmd, use caches during import cmd 2017-08-03 18:39:34 +02:00
akiva
4371367cd1 Makefile, README: remove evm target, add puppeth to table (#14886) 2017-08-03 13:58:35 +02:00
Jim McDonald
bc0e6a5e68 ethclient: add NetworkID method (#14791)
There is currently no simple way to obtain the network ID from a Client. 
This adds a NetworkID method that wraps the net_version JSON-RPC call.
2017-08-01 10:59:46 +02:00
Lewis Marshall
60c858a529 swarm/api: make api.NewManifest synchronous (#14880)
Previously, NewManifest was asynchronous so subsequent code which tried
to use the returned manifest could error as the manifest was not yet
persisted.
2017-07-31 15:58:19 +02:00
Lewis Marshall
e9b850805e cmd/swarm: support exporting, importing chunk db (#14868) 2017-07-31 13:23:44 +02:00
njupt-moon
53f3460ab5 core/asm: fix hex number lexing (#14861) 2017-07-31 13:02:36 +02:00
Felix Lange
bdf98b4fcd common: EIP55-compliant Address.Hex() (#14815)
This patch updates the Address type in common/types.go so that the Hex
function provides an EIP55-compliant output string. The implementation is pretty lightweight; 
on my laptop the benchmark gives 1100ns/op, with the majority of that value due to the Keccak hash.
2017-07-31 12:22:02 +02:00
bas-vk
c259e6874e light: update txpool signer to EIP155 (#14720) 2017-07-31 12:06:01 +02:00
Lee Hyeon
13cda8d9b6 Makefile: fixed GOBIN absolute path issue (#14854) 2017-07-31 12:00:17 +02:00
Mark
4f9789b28d core: avoid write existing block again (#14849) 2017-07-31 11:59:07 +02:00
Péter Szilágyi
ee748d1451 Merge pull request #14882 from am2rican5/rinkeby-genesis
mobile: add RinkebyGenesis method
2017-07-31 12:27:45 +03:00
am2rican5
0732ad4e47 mobile: add RinkebyGenesis method 2017-07-31 17:44:08 +09:00
Péter Szilágyi
3d32690b54 cmd, core, eth: journal local transactions to disk (#14784)
* core: reduce txpool event loop goroutines and sync structs

* cmd, core, eth: journal local transactions to disk

* core: journal replacement pending transactions too

* core: separate transaction journal from pool
2017-07-28 15:09:39 +02:00
Péter Szilágyi
a602ee90f2 Merge pull request #14858 from xmikus01/patch-1
trie: typo in comment
2017-07-26 09:40:41 +02:00
Péter Szilágyi
fc78ce61c0 Merge pull request #14859 from cdetrio/evm-flag-gasprice
core/vm/runtime: fix evm command to use --gasprice flag value
2017-07-26 09:40:05 +02:00
cdetrio
ffebf00114 core/vm/runtime: fix evm command to use --gasprice flag value 2017-07-25 13:08:29 -04:00
Petr Mikusek
99da85c895 trie: typo in comment 2017-07-25 19:02:40 +02:00
Lewis Marshall
f4841ff43d swarm/api/http: redirect root manifest requests to include trailing slash (#14806) 2017-07-25 11:51:26 +02:00
Leo Shklovskii
3a678a15c9 cmd/abigen: update generated go file header text (#14845)
As per https://golang.org/s/generatedcode. This will allow other tools
such as golint to properly ignore the files.
2017-07-24 14:09:03 +02:00
Felix Lange
3e0dbe0eaa core/vm: remove logging and add section labels to struct logs (#14782) 2017-07-19 14:32:45 +02:00
Chase Wright
1802682f65 node: Rename TrusterNodes (#14827)
* node: Rename TrusterNodes

* node: Rename TrusterNodes
2017-07-18 11:58:46 +03:00
Péter Szilágyi
4d2249773a Merge pull request #14824 from karalabe/faucet-ignore-whitespace
cmd/faucet: ignore whitespace in gist content
2017-07-17 21:19:16 +03:00
Péter Szilágyi
8a8fc5f8ef Merge pull request #14823 from karalabe/puppeth-limited-logging
cmd/puppeth: limit cotnainers to 10MB logs
2017-07-17 21:18:31 +03:00
Péter Szilágyi
671ba3791d cmd/faucet: ignore whitespace in gist content 2017-07-17 21:15:25 +03:00
Péter Szilágyi
9488e7fd5f cmd/puppeth: limit cotnainers to 10MB logs 2017-07-17 20:38:40 +03:00
Elias Naur
23c6fcdbe8 mobile: don't retain transient []byte in CallMsg.SetData (#14804)
* mobile: don't retain transient []byte in CallMsg.SetData

Go mobile doesn't copy []byte parameters, for performance and to allow
writes to the byte array be reflected in the native byte array.
Unfortunately, that means []byte arguments are only valid during the
call it is being passed into.

CallMsg.SetData retains such a byte array. Copy it instead

Fixes #14675

* mobile: copy all []byte arguments from gomobile

To avoid subtle errors when accidentially retaining an otherwise
transient byte slice coming from gomobile, copy all byte slices before
use.

* mobile: replace copySlice with common.CopyBytes
2017-07-17 15:25:46 +03:00
ligi
cf5d4b5541 mobile: use EIP155 signer (#14817)
* mobile: Use EIP155Signer - closes #14762

* mobile: Correctly fall back on HomesteadSigner when no chainID is passed in
2017-07-17 14:31:26 +03:00
Péter Szilágyi
b95c2b58f0 Merge pull request #14807 from Dexaran/master
README: get rid of the non-existent disasm command
2017-07-17 12:48:56 +03:00
Péter Szilágyi
8e9197f2a1 README: get rid of the on-existent disasm command 2017-07-17 12:48:12 +03:00
Péter Szilágyi
c65f10a17b Merge pull request #14733 from karalabe/metro-eip100
consensus/ethash, core: implement Metropolis EIP 100
2017-07-17 12:43:13 +03:00
Péter Szilágyi
a56f3dc0d9 core, ethclient: implement Metropolis EIP 98 (#14750)
Implements ethereum/EIPs#98
2017-07-17 10:34:53 +02:00
Martin Holst Swende
47359301a2 core: blocknumber in genesis as hex (#14812) 2017-07-17 10:33:13 +02:00
Jim McDonald
688ee6d1e5 cmd/geth: update tests for EIP55-compliant Address.Hex() 2017-07-16 13:29:20 +01:00
Jim McDonald
ad8d519eb5 common: tests for EIP55-compliant Address.Hex() 2017-07-16 13:28:22 +01:00
Jim McDonald
9e80d9bee1 common: Address.Hex() outputs EIP55-compliant string 2017-07-16 13:26:16 +01:00
Péter Szilágyi
0ff35e170d core: remove redundant storage of transactions and receipts (#14801)
* core: remove redundant storage of transactions and receipts

* core, eth, internal: new transaction schema usage polishes

* eth: implement upgrade mechanism for db deduplication

* core, eth: drop old sequential key db upgrader

* eth: close last iterator on successful db upgrage

* core: prefix the lookup entries to make their purpose clearer
2017-07-14 19:39:53 +03:00
Péter Szilágyi
8d6a5a3581 VERSION, params: begin 1.7.0 cycle (cannot downgrade) 2017-07-14 18:10:18 +03:00
Dexaran
33a24bb731 Update README.md 2017-07-14 11:56:08 +04:00
Dexaran
2d47c6bfde Update README.md 2017-07-14 11:55:10 +04:00
Dexaran
d68ad36bb9 Update README.md 2017-07-14 11:54:35 +04:00
Dexaran
df74a43396 Update README.md 2017-07-14 11:53:46 +04:00
Dexaran
01cb9948f1 Update README.md 2017-07-14 11:53:09 +04:00
Felix Lange
bf468a81ec params, VERSION: v1.6.8 unstable 2017-07-11 16:33:39 +02:00
Felix Lange
ab5646c532 params: v1.6.7 stable 2017-07-11 16:32:36 +02:00
Péter Szilágyi
3b25012481 Merge pull request #14792 from karalabe/slim-docker-image
dockerignore: ignore all git metadata and all tests
2017-07-11 17:07:01 +03:00
Péter Szilágyi
bd381be9c8 dockerignore: ignore all git metadata and all tests 2017-07-11 17:02:22 +03:00
Felix Lange
225de7ca0a tests: update tests and implement general state tests (#14734)
Tests are now included as a submodule. This should make updating easier
and removes ~60MB of JSON data from the working copy.

State tests are replaced by General State Tests, which run the same test
with multiple fork configurations.

With the new test runner, consensus tests are run as subtests by walking
json files. Many hex issues have been fixed upstream since the last
update and most custom parsing code is replaced by existing JSON hex
types. Tests can now be marked as 'expected failures', ensuring that
fixes for those tests will trigger an update to test configuration. The
new test runner also supports parallel execution and the -short flag.
2017-07-11 13:49:14 +02:00
Péter Szilágyi
bd01cd7183 vendor: update go-stack to fix a sigpanic panic (#14790) 2017-07-11 13:43:33 +02:00
Daniel Sloof
0958770625 internal/web3ext: fix debug.traceBlockFromFile wrapper (#14774)
As stated in the documentation, this method should be called traceBlockFromFile
and not traceBlockByFile. Previously this would result in a 'The method ... does
not exist/is not available' error.
2017-07-10 12:47:50 +02:00
Péter Szilágyi
4f7a38001f Merge pull request #14737 from holiman/txpool_localaccounts
Txpool localaccounts
2017-07-10 12:43:23 +03:00
Emin Mahrt
65f0e905dd README: add missing full stop (#14766) 2017-07-07 16:41:26 +02:00
Nick Johnson
4b8860a7b4 Merge pull request #14723 from Arachnid/downloadrefactor
Refactor downloader to use interfaces instead of callbacks
2017-07-06 12:40:22 +01:00
Péter Szilágyi
34ec9913f6 core: test locals support in txpool queue limits, fix
The commit reworks the transaction pool queue limitation tests
to cater for testing local accounts, also testing the nolocal flag.

In addition, it also fixes a panic if local transactions exceeded
the global queue allowance (no accounts left to drop from) and also
fixes queue eviction to operate on all accounts, not just the one
being updated.
2017-07-06 11:51:59 +03:00
ligi
f25486c3fb core: fix typo in error message (#14763) 2017-07-06 00:19:38 +02:00
Péter Szilágyi
88b4fe7d21 core: handle nolocals during add, exepmt locals from expiration 2017-07-05 17:16:42 +03:00
Péter Szilágyi
5e38f7a664 cmd, core: add --txpool.nolocals to disable local price exemptions 2017-07-05 17:06:05 +03:00
Péter Szilágyi
4c1d0b164b eth: drop leftover from previous nonce protection scheme 2017-07-05 16:53:40 +03:00
Péter Szilágyi
48ee7f9de7 core, eth, les: polish txpool API around local/remote txs 2017-07-05 16:51:55 +03:00
Nick Johnson
fe13949d9d eth/downloader: Doc fixes 2017-07-05 11:13:16 +01:00
Péter Szilágyi
138f26c93a Merge pull request #14749 from karalabe/disable-metro-allprotocols
params: remove redundant consts, disable metro on AllProtocolChanges
2017-07-04 14:11:04 +03:00
Péter Szilágyi
8f12d76a47 params: remove redundant consts, disable metro on AllProtocolChanges 2017-07-04 12:28:58 +03:00
Nick Johnson
be8f8409bc eth/downloader, les, light: Changes in response to review 2017-07-03 15:17:12 +01:00
Martin Holst Swende
a633a2d7ea core: Prevent local tx:s from being discarded 2017-06-30 22:55:10 +02:00
Martin Holst Swende
67aff49822 core: Change local-handling to use sender-account instead of tx hashes 2017-06-30 22:43:26 +02:00
Péter Szilágyi
8c313eed26 consensus, core: EIP 100 polishes, fix chain maker diff
This PR polishes the EIP 100 difficulty adjustment algorithm
to match the same mechanisms as the Homestead was implemented
to keep the code uniform. It also avoids a few memory allocs
by reusing big1 and big2, pulling it out of the common package
and into ethash.

The commit also fixes chain maker to forward the uncle hash
when creating a simulated chain (it wasn't needed until now
so we just skipped a copy there).
2017-06-30 16:42:09 +03:00
Jeffrey Wilcke
c4d28aee9b consensus/ethash: implement Metropolis EIP 100 2017-06-30 16:41:25 +03:00
Péter Szilágyi
a0aa071ca6 Merge pull request #14732 from ethersphere/swarm-remove-ethapi
cmd/swarm: Exit if --ethapi is set
2017-06-30 13:06:52 +03:00
Lewis Marshall
c7041fe145 cmd/swarm: Exit if --ethapi is set
The previous attempt to use --ethapi as a fallback if --ens-api is not
set does not work because --ens-api has a default value, and also
setting --ens-api to "" is the suggested way to disable ENS lookups.

Signed-off-by: Lewis Marshall <lewis@lmars.net>
2017-06-30 10:16:03 +01:00
Péter Szilágyi
41318f3776 Merge pull request #14646 from ethersphere/swarm-ens-api
cmd/swarm: Support using Mainnet for resolving ENS names
2017-06-29 19:09:01 +03:00
Péter Szilágyi
65b96dc4b9 Merge pull request #14727 from holiman/count_txs_right
Fix error when reporting numer of txs in imported blocks
2017-06-29 16:49:43 +03:00
Martin Holst Swende
8bbd598ef4 core: fix an off-by-one when the block import counts blocks 2017-06-29 14:19:10 +02:00
Nick Johnson
ae11545bc5 eth, les: Refactor downloader peer to use structs 2017-06-29 12:49:18 +01:00
Nick Johnson
0550957989 eth, les, light: Refactor downloader to use blockchain interface 2017-06-28 15:58:41 +01:00
Péter Szilágyi
dfd076244d Merge pull request #14718 from holiman/gascalc_fix
core/vm: fix overflow in gas calculation formula
2017-06-28 13:12:13 +03:00
Martin Holst Swende
6dc32e897a core/vm: add benchmarks for some ops and precompiles (#14641) 2017-06-28 11:45:45 +02:00
Martin Holst Swende
e4301564c2 core/vm : fix testcase for gas calculation 2017-06-28 10:47:07 +02:00
Martin Holst Swende
bae7565231 core/vm: fix overflow in gas calculation formula 2017-06-28 09:51:31 +02:00
Felix Lange
9e5f03b6c4 core/state: access trie through Database interface, track errors (#14589)
With this commit, core/state's access to the underlying key/value database is
mediated through an interface. Database errors are tracked in StateDB and
returned by CommitTo or the new Error method.

Motivation for this change: We can remove the light client's duplicated copy of
core/state. The light client now supports node iteration, so tracing and storage
enumeration can work with the light client (not implemented in this commit).
2017-06-27 15:57:06 +02:00
Péter Szilágyi
bb366271fe Merge pull request #14686 from fjl/hexutil-json-type-error
common/hexutil: wrap errors in json.UnmarshalTypeError
2017-06-27 15:02:43 +03:00
Felix Lange
4a741df757 common/hexutil: wrap errors in json.UnmarshalTypeError
This adds type and struct field context to error messages.
Instead of "hex string of odd length" users will now see "json: cannot
unmarshal hex string of odd length into Go struct field SendTxArgs.from
of type common.Address".
2017-06-27 13:15:12 +02:00
RJ Catalano
5421a08d2f accounts/abi: reorganizing package with small fixes (#14610)
* accounts/abi: reorganizing package and some notes and a quick correction of name.

Signed-off-by: RJ Catalano <rj@monax.io>

get rid of some imports

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: move file names

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: fix boolean decode function

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: fix for the array set and for creating a bool

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: be very very very correct

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: fix up error message and variable names

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: take out unnecessary argument in pack method

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: add bool unpack test and add a panic to readBool function

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: fix panic message

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: change from panic to basic error

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: fix nil to false

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: fill out type regex tests and fill with the correct type for integers

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: move packNumbers into pack.go.

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: separation of the testing suite into appropriately named files.

Signed-off-by: RJ Catalano <rj@monax.io>

* account/abi: change to hex string tests.

Signed-off-by: RJ Catalano <rj@monax.io>

* account/abi: fix up rest of tests to hex

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: declare bool at the package level

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: use errors package in the error file.

Signed-off-by: RJ Catalano <rj@monax.io>

* accounts/abi: fix ugly hack and fix error type declaration.

Signed-off-by: RJ Catalano <rj@monax.io>
2017-06-27 11:05:33 +03:00
Addy Yeow
cf611c50b9 build: fix devel golang detection on debian/ubuntu (#14711) 2017-06-27 09:11:41 +02:00
Péter Szilágyi
c008176f9f Merge pull request #14690 from karalabe/faucet-key-reuse
cmd/puppeth: fix key reuse during faucet deploys
2017-06-26 14:03:46 +03:00
Lewis Marshall
f3359d5e58 cmd/swarm: Support using Mainnet for resolving ENS names
Signed-off-by: Lewis Marshall <lewis@lmars.net>
2017-06-26 12:51:33 +02:00
Péter Szilágyi
feb2932706 Merge pull request #14540 from bas-vk/whisper-api
whisperv5: integrate whisper and implement API
2017-06-26 13:44:35 +03:00
Péter Szilágyi
ea1d1825a8 cmd/geth: fix whisper flag group capitalization 2017-06-26 13:40:43 +03:00
Péter Szilágyi
f321ed23fb Merge pull request #14687 from markya0616/unused_events
core: remove unused events
2017-06-26 13:27:39 +03:00
bloonfield
413dc1d265 rpc: fix closure problem in batch processing (#14688)
Demo of the issue: https://play.golang.org/p/EeTLFfppqC
2017-06-26 12:26:22 +03:00
Péter Szilágyi
fdf2184b1e Merge pull request #14697 from homotopycolimit/master
swarm/storage: remove panic on invalid chunk
2017-06-26 12:21:11 +03:00
Aron
3c7338d6c8 Makefile: add make swarm command (#14698)
* Makefile: add make swarm command

* Makefile: minor code formatting polishes
2017-06-26 12:19:53 +03:00
G. Kay Lee
ef8d4711d5 Update README.md (#14701)
README: change heading to "Go Ethereum"
2017-06-26 12:17:06 +03:00
aron
caa00b7e6d swarm/storage: remove panic on invalid chunk 2017-06-25 16:10:54 +02:00
Péter Szilágyi
5603eb9116 cmd/puppeth: fix key reuse during faucet deploys 2017-06-23 13:34:21 +03:00
Felix Lange
78c04c920d params, VERSION: 1.6.7 unstable 2017-06-23 11:28:43 +02:00
Felix Lange
10a45cb59b params: 1.6.6 stable 2017-06-23 11:26:54 +02:00
Péter Szilágyi
cd88f69715 Merge pull request #14596 from markya0616/valid_clique_vote
consensus/clique: choose valid votes
2017-06-23 11:21:38 +03:00
Péter Szilágyi
46d0d04f97 Merge pull request #14685 from karalabe/ethdb-metrics-fail-fix
eth: gracefully error if database cannot be opened
2017-06-23 11:10:29 +03:00
Péter Szilágyi
514659a023 consensus/clique: minor cleanups 2017-06-23 11:06:38 +03:00
Felix Lange
01c9cf1cb5 node: don't return non-nil database on error 2017-06-23 09:56:30 +02:00
Péter Szilágyi
b751cf3901 Merge pull request #14681 from fjl/build-fixup
travis.yml, cmd/swarm: fix Travis CI build
2017-06-23 10:30:27 +03:00
Bas van Kervel
b6e99deee9 whisper: renamed Info#Message to Info#Messages 2017-06-23 09:18:02 +02:00
Péter Szilágyi
d40179f882 eth: gracefully error if database cannot be opened 2017-06-23 10:12:41 +03:00
mark.lin
beb708e6d7 core: remove unused events 2017-06-23 10:39:38 +08:00
Felix Lange
f2c5b2cc1c travis.yml: add fakeroot to launchpad builder 2017-06-22 22:21:59 +02:00
Felix Lange
a4277450b2 cmd/swarm: disable TestCLISwarmUp because it's flaky 2017-06-22 22:17:53 +02:00
Péter Szilágyi
b664bedcf2 Merge pull request #14673 from holiman/txfix
core: add testcase for txpool
2017-06-22 23:01:43 +03:00
Péter Szilágyi
eebde1a2e2 core: ensure transactions correctly drop on pool limiting 2017-06-22 21:03:54 +03:00
Martin Holst Swende
b0b3cf2eeb core: add testcase for txpool 2017-06-22 20:36:07 +03:00
Péter Szilágyi
c98d9b49bf Merge pull request #14677 from karalabe/miner-cli-gasprice
cmd/geth: corrently init gas price for CLI CPU mining
2017-06-22 15:54:24 +03:00
Felix Lange
0042f13d47 eth/downloader: separate state sync from queue (#14460)
* eth/downloader: separate state sync from queue

Scheduling of state node downloads hogged the downloader queue lock when
new requests were scheduled. This caused timeouts for other requests.
With this change, state sync is fully independent of all other downloads
and doesn't involve the queue at all.

State sync is started and checked on in processContent. This is slightly
awkward because processContent doesn't have a select loop. Instead, the
queue is closed by an auxiliary goroutine when state sync fails. We
tried several alternatives to this but settled on the current approach
because it's the least amount of change overall.

Handling of the pivot block has changed slightly: the queue previously
prevented import of pivot block receipts before the state of the pivot
block was available. In this commit, the receipt will be imported before
the state. This causes an annoyance where the pivot block is committed
as fast block head even when state downloads fail. Stay tuned for more
updates in this area ;)

* eth/downloader: remove cancelTimeout channel

* eth/downloader: retry state requests on timeout

* eth/downloader: improve comment

* eth/downloader: mark peers idle when state sync is done

* eth/downloader: move pivot block splitting to processContent

This change also ensures that pivot block receipts aren't imported
before the pivot block itself.

* eth/downloader: limit state node retries

* eth/downloader: improve state node error handling and retry check

* eth/downloader: remove maxStateNodeRetries

It fails the sync too much.

* eth/downloader: remove last use of cancelCh in statesync.go

Fixes TestDeliverHeadersHang*Fast and (hopefully)
the weird cancellation behaviour at the end of fast sync.

* eth/downloader: fix leak in runStateSync

* eth/downloader: don't run processFullSyncContent in LightSync mode

* eth/downloader: improve comments

* eth/downloader: fix vet, megacheck

* eth/downloader: remove unrequested tasks anyway

* eth/downloader, trie: various polishes around duplicate items

This commit explicitly tracks duplicate and unexpected state
delieveries done against a trie Sync structure, also adding
there to import info logs.

The commit moves the db batch used to commit trie changes one
level deeper so its flushed after every node insertion. This
is needed to avoid a lot of duplicate retrievals caused by
inconsistencies between Sync internals and database. A better
approach is to track not-yet-written states in trie.Sync and
flush on commit, but I'm focuing on correctness first now.

The commit fixes a regression around pivot block fail count.
The counter previously was reset to 1 if and only if a sync
cycle progressed (inserted at least 1 entry to the database).
The current code reset it already if a node was delivered,
which is not stong enough, because unless it ends up written
to disk, an attacker can just loop and attack ad infinitum.

The commit also fixes a regression around state deliveries
and timeouts. The old downloader tracked if a delivery is
stale (none of the deliveries were requestedt), in which
case it didn't mark the node idle and did not send further
requests, since it signals a past timeout. The current code
did mark it idle even on stale deliveries, which eventually
caused two requests to be in flight at the same time, making
the deliveries always stale and mass duplicating retrievals
between multiple peers.

* eth/downloader: fix state request leak

This commit fixes the hang seen sometimes while doing the state
sync. The cause of the hang was a rare combination of events:
request state data from peer, peer drops and reconnects almost
immediately. This caused a new download task to be assigned to
the peer, overwriting the old one still waiting for a timeout,
which in turned leaked the requests out, never to be retried.
The fix is to ensure that a task assignment moves any pending
one back into the retry queue.

The commit also fixes a regression with peer dropping due to
stalls. The current code considered a peer stalling if they
timed out delivering 1 item. However, the downloader never
requests only one, the minimum is 2 (attempt to fine tune
estimated latency/bandwidth). The fix is simply to drop if
a timeout is detected at 2 items.

Apart from the above bugfixes, the commit contains some code
polishes I made while debugging the hang.

* core, eth, trie: support batched trie sync db writes

* trie: rename SyncMemCache to syncMemBatch
2017-06-22 15:26:03 +03:00
Péter Szilágyi
d432688886 cmd/geth: corrently init gas price for CLI CPU mining 2017-06-22 14:58:07 +03:00
Péter Szilágyi
58a1e13e6d Merge pull request #14657 from markya0616/refactor_clique
consensus/clique: fix typo and don't need to add snapshot into recents again
2017-06-21 17:58:15 +03:00
Lewis Marshall
a1f3878ec5 swarm/test: add integration test for 'swarm up' (#14353) 2017-06-21 14:54:23 +02:00
Maximilian Meister
a20a02ce0b README: document new config file option (#14348) 2017-06-21 14:53:08 +02:00
Martin Holst Swende
9a44e1035e cmd/evm, core/vm: add --nomemory, --nostack to evm (#14617) 2017-06-21 14:52:31 +02:00
Bas van Kervel
c62d5422bb whisper: use hexutil.UnmarshalFixedText for topic parsing 2017-06-21 12:58:00 +02:00
Péter Szilágyi
9012863ad7 Merge pull request #14667 from fjl/swarm-fuse-cleanup
swarm/fuse: simplify externalUnmount, use subtests
2017-06-21 13:51:00 +03:00
Felföldi Zsolt
a5d08c893d les: code refactoring (#14416)
This commit does various code refactorings:

- generalizes and moves the request retrieval/timeout/resend logic out of LesOdr
  (will be used by a subsequent PR)
- reworks the peer management logic so that all services can register with
  peerSet to get notified about added/dropped peers (also gets rid of the ugly
  getAllPeers callback in requestDistributor)
- moves peerSet, LesOdr, requestDistributor and retrieveManager initialization
  out of ProtocolManager because I believe they do not really belong there and the
  whole init process was ugly and ad-hoc
2017-06-21 12:27:38 +02:00
Bas van Kervel
a4e4c76cb3 whisper: use syncmap for dynamic configuration options 2017-06-21 11:15:47 +02:00
Bas van Kervel
7a11e86442 whisper: move flags from whisper package to utils 2017-06-21 10:49:14 +02:00
Bas van Kervel
4a1d516d78 whisper: renamed errors 2017-06-21 10:32:36 +02:00
Bas van Kervel
b6b0e00198 whisper: fallback to default config if none is specified 2017-06-21 10:24:34 +02:00
Bas van Kervel
3d66ba56ef whisper: remove obsolete api tests 2017-06-21 10:23:45 +02:00
Bas van Kervel
767dc6c73d whisper: remove gencodec override for config 2017-06-21 10:11:54 +02:00
Bas van Kervel
36e7963467 whisper: move ShhClient to its own package 2017-06-21 10:11:46 +02:00
Felix Lange
98e101ef8e swarm/fuse: use subtests 2017-06-21 09:56:58 +02:00
Felix Lange
50c18e6eb8 swarm/fuse: simplify externalUnmount
The code looked for /usr/bin/diskutil on darwin, but it's actually
located in /usr/sbin. Fix that by not specifying the absolute path.
Also remove weird timeout construction and extra whitespace.
2017-06-21 09:56:58 +02:00
Jim McDonald
60e27b51bc ethclient: fix TransactionByHash pending return value. (#14663)
As per #14661 TransactionByHash always returns false for pending.
This uses blockNumber rather than blockHash to ensure that it returns
the correct value for pending and will not suffer side-effects if
eth_getTransactionByHash is fixed in future.
2017-06-21 09:53:50 +02:00
Felix Lange
693d9ccbfb trie: more node iterator improvements (#14615)
* ethdb: remove Set

Set deadlocks immediately and isn't part of the Database interface.

* trie: add Err to Iterator

This is useful for testing because the underlying NodeIterator doesn't
need to be kept in a separate variable just to get the error.

* trie: add LeafKey to iterator, panic when not at leaf

LeafKey is useful for callers that can't interpret Path.

* trie: retry failed seek/peek in iterator Next

Instead of failing iteration irrecoverably, make it so Next retries the
pending seek or peek every time.

Smaller changes in this commit make this easier to test:

* The iterator previously returned from Next on encountering a hash
  node. This caused it to visit the same path twice.
* Path returned nibbles with terminator symbol for valueNode attached
  to fullNode, but removed it for valueNode attached to shortNode. Now
  the terminator is always present. This makes Path unique to each node
  and simplifies Leaf.

* trie: add Path to MissingNodeError

The light client trie iterator needs to know the path of the node that's
missing so it can retrieve a proof for it. NodeIterator.Path is not
sufficient because it is updated when the node is resolved and actually
visited by the iterator.

Also remove unused fields. They were added a long time ago before we
knew which fields would be needed for the light client.
2017-06-20 18:26:09 +02:00
mark.lin
5c53a5be66 consensus/clique: fix typo and don't add snapshot into recents again 2017-06-20 10:20:45 +08:00
Péter Szilágyi
431cf2a1e4 Merge pull request #14635 from necaremus/patch-1
cmd/geth: fixed a minor typo in the comments
2017-06-16 17:11:54 +03:00
necaremus
4f77857f74 cmd/geth: fixed a minor typo in the comments 2017-06-16 15:03:19 +02:00
Alan Chen
fade09a7ff eth: remove les server from protocol manager (#14625) 2017-06-15 15:28:57 +02:00
Bas van Kervel
b58a501673 whisperv5: integrate whisper and add whisper RPC simulator 2017-06-15 11:53:15 +02:00
mark.lin
db6e695002 consensus/clique: choose valid votes 2017-06-14 16:49:33 +08:00
Péter Szilágyi
335abdceb1 Merge pull request #14581 from holiman/byte_opt
core/vm: improve opByte
2017-06-13 14:44:19 +03:00
Péter Szilágyi
732273094c Merge pull request #14604 from bas-vk/mobile-getfrom
mobile: use EIP155 signer for determining sender
2017-06-13 14:09:25 +03:00
Péter Szilágyi
b8793edd83 mobile: add a regression test for signer recovery 2017-06-13 13:39:39 +03:00
Bas van Kervel
eb92522278 mobile: use EIP155 signer for determining sender 2017-06-13 09:13:59 +02:00
S. Matthew English
061889d4ea rlp, trie, contracts, compression, consensus: improve comments (#14580) 2017-06-12 14:45:17 +02:00
Péter Szilágyi
e3dfd55820 Merge pull request #14598 from konradkonrad/fix_makedag
consensus/ethash, cmd/geth: Fix `makedag` epoch
2017-06-12 13:34:26 +03:00
Konrad Feldmeier
2fefe4baa0 consensus: Fix makedag epoch
`geth makedag <blocknumber> <path>` was creating DAGs for
`<blocknumber>/<epoch_length> + 1`, hence
it was impossible to create an epoch 0 DAG.

This fixes the calculations in `consensus/ethash/ethash.go` for
`MakeDataset` and `MakeCache`, and applies `gofmt`.
2017-06-12 11:15:16 +02:00
Martin Holst Swende
ac9865791a core/vm, common/math: Add doc about Byte, fix format 2017-06-08 23:16:05 +02:00
Martin Holst Swende
80f7c6c299 cmd/evm: add --prestate, --sender, --json flags for fuzzing (#14476) 2017-06-07 17:09:08 +02:00
bailantaotao
bc24b7a912 core/types: use Header.Hash for block hashes (#14587)
Fixes #14586
2017-06-07 12:06:25 +02:00
Martin Holst Swende
1496b3aff6 common/math, core/vm: Un-expose bigEndianByteAt, use correct terms for endianness 2017-06-06 18:38:38 +02:00
Lewis Marshall
1e9f86b49e cmd/swarm: fix error handling in 'swarm up' (#14557)
The error returned by client.Upload was previously being ignored due to becoming
out of scope outside the if statement. This has been fixed by instead defining a
function which returns the hash and error (rather than trying to set the hash in
each branch of the if statement).
2017-06-06 09:39:10 +02:00
Péter Szilágyi
65ea913e29 Merge pull request #14583 from ethersphere/core-log-fixes
core: Fix VM error logging
2017-06-06 10:31:27 +03:00
FaceHo
9a0e433b13 accounts: fix spelling error (#14567) 2017-06-06 09:28:47 +02:00
Lewis Marshall
04d2de9119 core: Fix VM error logging
Signed-off-by: Lewis Marshall <lewis@lmars.net>
2017-06-05 23:51:32 +01:00
Martin Holst Swende
f4b5f67ee0 core/vm: improved jumpdest analysis 2017-06-05 09:15:46 +02:00
Martin Holst Swende
3285a0fda3 core/vm, common/math: Add fast getByte for bigints, improve opByte 2017-06-05 08:44:11 +02:00
Péter Szilágyi
6171d01b11 VERSION, params: begin Geth 1.6.6 release cycle 2017-06-01 22:08:19 +03:00
Péter Szilágyi
cf87713dd4 params: mark Geth v1.6.5 stable (Hat Trick) 2017-06-01 21:48:47 +03:00
Péter Szilágyi
ac92d7c411 Merge pull request #14570 from Arachnid/jumpdestanalysis
core/vm: Use a bitmap instead of a map for jumpdest analysis
2017-06-01 21:44:50 +03:00
Nick Johnson
d5a79934dc core/vm: Use a bitmap instead of a map for jumpdest analysis
t push --force
2017-06-01 19:14:05 +01:00
Péter Szilágyi
0424192e61 VERSION, params: begin geth 1.6.5 cycle 2017-06-01 17:37:44 +03:00
Péter Szilágyi
9c2882b2e5 params: Geth 1.6.4 stable (hotfix) 2017-06-01 17:33:17 +03:00
Martin Holst Swende
1a0eb903f1 internal/ethapi: initialize account mutex in lock properly 2017-06-01 17:16:12 +03:00
Lewis Marshall
0036e2a747 swarm/dev: add development environment (#14332)
This PR adds a Swarm development environment which can be run in a
Docker container and provides scripts for building binaries and running
Swarm clusters.
2017-06-01 12:52:18 +02:00
Péter Szilágyi
727eadacca VERSION, params: begin Geth 1.6.4 release cycle 2017-06-01 11:43:57 +03:00
Péter Szilágyi
99cba96f26 params: release Geth 1.6.3 - Covfefe 2017-06-01 11:41:48 +03:00
Péter Szilágyi
f272879e5a Merge pull request #14565 from karalabe/relax-privkey-checks
accounts/keystore, crypto: don't enforce key checks on existing keyfiles
2017-06-01 11:14:11 +03:00
Péter Szilágyi
72dd51e25a accounts/keystore, crypto: don't enforce key checks on existing keyfiles 2017-06-01 11:11:06 +03:00
Péter Szilágyi
799a469000 Merge pull request #14561 from karalabe/txpool-perf-fix
core: reduce transaction reorganization overhead
2017-06-01 10:33:47 +03:00
Péter Szilágyi
f4d81178d8 Merge pull request #14563 from karalabe/ethstats-reduce-traffic-2
ethstats: reduce ethstats traffic by trottling reports
2017-06-01 10:33:21 +03:00
Péter Szilágyi
310d2e7ef4 Merge pull request #14564 from karalabe/fix-1.6-docker
cotnainers/docker: fix the legacy alpine image before dropping
2017-06-01 10:33:03 +03:00
Péter Szilágyi
3ecde4e2aa cotnainers/docker: fix the legacy alpine image before dropping 2017-06-01 00:21:47 +03:00
Péter Szilágyi
a355b401db ethstats: reduce ethstats traffic by trottling reports 2017-06-01 00:16:19 +03:00
Péter Szilágyi
cba33029a8 core: only reorg changed account, not all 2017-05-31 23:26:24 +03:00
Péter Szilágyi
9702badd83 core: don't uselessly recheck transactions on dump 2017-05-31 21:29:50 +03:00
Felix Lange
067dc2cbf5 params, VERSION: 1.6.3 unstable 2017-05-31 05:47:35 +02:00
Felix Lange
65979770e6 params: 1.6.2 stable 2017-05-31 05:45:13 +02:00
Péter Szilágyi
41bdf49eed Merge pull request #14516 from holiman/noncefixes
internal/ethapi: add mutex around signing + nonce assignment
2017-05-30 18:15:57 +03:00
Martin Holst Swende
ea11f7dd7a internal/ethapi: add mutex around signing + nonce assignment
This prevents concurrent assignment of identical nonces when automatic
assignment is used.
2017-05-30 16:43:38 +02:00
Péter Szilágyi
8df24760d7 Merge pull request #14553 from karalabe/puppeth-key-check
cmd/puppeth: fix improper key validation for remotes
2017-05-30 14:50:48 +03:00
Péter Szilágyi
71814bf6c4 Merge pull request #14547 from karalabe/txpool-gas-decrease
core: check for gas limit exceeding txs too on new block
2017-05-30 14:50:27 +03:00
Péter Szilágyi
ec1700600a cmd/puppeth: fix improper key validation for remotes 2017-05-30 14:24:01 +03:00
Péter Szilágyi
b0f30b0b37 Merge pull request #14545 from karalabe/clique-cache-signatures
consensus/clique: cache block signatures for fast checks
2017-05-30 12:56:57 +03:00
Péter Szilágyi
e96f2981e2 Merge pull request #14548 from karalabe/ethstats-no-txs
ethstats: don't report transaction content, only hash
2017-05-30 12:54:00 +03:00
Péter Szilágyi
09d59da3a1 ethstats: don't report transaction content, only hash 2017-05-30 02:15:40 +03:00
Péter Szilágyi
280609c99b core: check for gas limit exceeding txs too on new block 2017-05-30 00:31:37 +03:00
Péter Szilágyi
309da541de consensus/clique: cache block signatures for fast checks 2017-05-29 22:07:02 +03:00
Péter Szilágyi
dd06c85843 Merge pull request #14523 from karalabe/txpool-cli-flags
cmd, core, eth: configurable txpool parameters
2017-05-29 11:42:48 +03:00
Péter Szilágyi
ae40d51410 Merge pull request #14539 from karalabe/txpool-inspec-nonces
internal/ethapi: fix tx nonces in pool inspect/content
2017-05-29 11:37:34 +03:00
Péter Szilágyi
b865fad888 Merge pull request #14537 from karalabe/setgasprice-durning-nomine
eth: update default gas price when not mining too
2017-05-29 11:37:26 +03:00
Péter Szilágyi
afb17cf071 Merge pull request #14524 from karalabe/noimport-during-fastsync
eth: don't import propagated blocks during fastsync
2017-05-29 11:37:08 +03:00
Péter Szilágyi
08959bbc70 cmd, core, eth: configurable txpool parameters 2017-05-29 11:29:46 +03:00
Péter Szilágyi
673c92db6b internal/ethapi: fix tx nonces in pool inspect/content 2017-05-29 11:17:31 +03:00
Péter Szilágyi
c2a494c743 eth: update default gas price when not mining too 2017-05-29 10:21:34 +03:00
Péter Szilágyi
afdd23b5ca eth: don't import propagated blocks during fastsync 2017-05-26 16:04:12 +03:00
Nick Johnson
cb809c03da Merge pull request #14517 from Ali92hm/master
Improved Dockerfile?
2017-05-26 10:54:41 +01:00
Ali92hm
45421d3130 dockerfile: expose 30303/udp 2017-05-25 12:34:29 -07:00
Ali92hm
115e7d71cc dockerfile: cp geth to /usr/local/bin 2017-05-25 12:34:28 -07:00
Péter Szilágyi
dd5ed01f3b Merge pull request #14514 from karalabe/go1.8.3
travis, appveyor: bump to Go 1.8.3, Android NDK 14b
2017-05-25 17:42:40 +03:00
Péter Szilágyi
b7ff0d42e3 Merge pull request #14515 from karalabe/golint-tooooolong
core: fix various golint warnings and errors
2017-05-25 17:40:51 +03:00
Péter Szilágyi
c98bce709c core: fix minor accidental typos and comment errors 2017-05-25 17:22:45 +03:00
changhong
17f0b11942 core: typos and comments improve
1. fix typos
2. methods recevier of struct should be same
3. comments improve

(cherry picked from commit 1ba9795395)
2017-05-25 17:14:33 +03:00
Péter Szilágyi
6231edcbab travis, appveyor: bump to Go 1.8.3, Android NDK 14b 2017-05-25 17:05:33 +03:00
Péter Szilágyi
07aae19e5d Merge pull request #14446 from bas-vk/cli-help
Rewrite templates for (sub)commands help section
2017-05-25 13:58:55 +03:00
Péter Szilágyi
b596b4ba5b Merge pull request #14513 from obscuren/allocate-stack
core/vm: allocate stack to 1024
2017-05-25 13:22:56 +03:00
Or Rikon
8b1e4c4c5e README: corrected attach example (#14512) 2017-05-25 13:22:26 +03:00
Jeffrey Wilcke
846d091bd2 core/vm: allocate stack to 1024
Pre allocate the stack to 1024 optimising stack pushing, reducing calls
to runtime.makeslice and runtime.mallocgc
2017-05-25 11:37:04 +02:00
Bas van Kervel
a346aedb90 cmd/geth: reorganise help section for new cli flag handling 2017-05-25 09:15:51 +02:00
Felix Lange
ef25b826e6 Merge pull request #14502 from karalabe/mobile-import-ecdsa
Enforce 256 bit keys on raw import, support raw mobile imports
2017-05-24 22:30:47 +02:00
Felix Lange
261b3e2351 Merge pull request #14336 from obscuren/metropolis-preparation
consensus, core/*, params: metropolis preparation refactor
2017-05-24 22:28:22 +02:00
Péter Szilágyi
344f25fb3e Merge pull request #14507 from karalabe/faucet-misspell
cmd/faucet: fix a few typos
2017-05-24 17:14:21 +03:00
Péter Szilágyi
1afaea4bfe cmd/faucet: fix a few typos 2017-05-24 17:12:07 +03:00
Felix Lange
11cf5b7ead consensus/ethash: fix TestCalcDifficulty 2017-05-24 15:40:54 +02:00
Felix Lange
069cb661c3 crypto/bn256: fix go vet false positive
Also add the package to the license tool ignore list.
2017-05-24 15:40:26 +02:00
Péter Szilágyi
3b8915e387 Merge pull request #14504 from bas-vk/wallet-import
cmd/geth: reintroduce wallet import subcommand
2017-05-24 13:00:22 +03:00
Bas van Kervel
437ceaa9be cmd/geth: reintroduce wallet import subcommand 2017-05-23 17:45:26 +02:00
Péter Szilágyi
136f78ff0a mobile: support importing flat ecdsa keyst too 2017-05-23 14:58:28 +03:00
Péter Szilágyi
aa73420207 accounts/keystore, crypto: enforce 256 bit keys on import 2017-05-23 14:58:03 +03:00
Péter Szilágyi
3556962053 Merge pull request #14501 from sqli-nantes/master
mobile: manage FilterQuery enabling contract events subscription
2017-05-23 13:47:22 +03:00
Jeffrey Wilcke
e1e87d8b1a common: fixed byte padding functions
Byte padding function should return the given slice if the length is
smaller or equal rather than *only* smaller than.

This fix improves almost all EVM push operations.
2017-05-23 11:24:07 +02:00
Nicolas Guillaume
30cc1c3bf0 mobile: Add management methods to {Addresses,Topics,Hashes} structures 2017-05-23 11:16:25 +02:00
Jeffrey Wilcke
10582a97ca core/vm: expose intpool to stack dup method
Improve the duplication method of the stack to reuse big ints by passing
in an existing integer pool.
2017-05-23 10:52:11 +02:00
Jeffrey Wilcke
e16a7ef60f core/vm: capped int pool 2017-05-23 10:40:09 +02:00
Jeffrey Wilcke
a816e75662 core/vm: improved push instructions
Improved push instructions by removing unnecessary big int allocations
and by making it int instead of big.Int
2017-05-23 10:39:53 +02:00
Jeffrey Wilcke
3ee75bec9f cmd/evm: added mem/cpu profiling 2017-05-23 10:17:55 +02:00
Valentin Wüstholz
04b668b232 core/vm: improve error message for invalid opcodes 2017-05-22 17:48:07 +02:00
Nicolas Guillaume
da636c53d6 mobile: Allows mobile clients to create custom FilterQueries 2017-05-22 17:12:36 +02:00
Lewis Marshall
2a41e76b39 swarm/api: Fix adding paths which exist as manifests (#14482)
Signed-off-by: Lewis Marshall <lewis@lmars.net>
2017-05-22 08:57:03 +02:00
Lewis Marshall
4a2c17b1ab cmd/swarm: Add --httpaddr flag (#14475)
Fixes #14474.

Signed-off-by: Lewis Marshall <lewis@lmars.net>
2017-05-22 08:56:40 +02:00
Dave Conroy
bc75351edf README: fixing typo in documentation (#14493) 2017-05-22 08:47:27 +02:00
Ali Hajimirza
33b158e0ed discover: Changed Logging from Debug to Info (#14485) 2017-05-20 13:10:59 +02:00
Martin Holst Swende
83721a95ce internal/ethapi: lock when auto-filling transaction nonce (#14483)
More context in the bug This solves the problems of transactions being
submitted simultaneously, and getting the same nonce, due to the gap (due to
signing) between nonce-issuance and nonce-update. With this PR, a lock will
need to be acquired whenever a nonce is used, and released when the transaction
is submitted or errors out.
2017-05-19 15:03:56 +02:00
Jeffrey Wilcke
e7119ce12d core/state: fixed (self)destructed objects
Add the object to the list of destructed objects during a selfdestruct /
suicide operation and also remove it from the list once the journal
reverts.
2017-05-18 09:05:58 +02:00
Jeffrey Wilcke
a5f6a1cb7c consensus, core, core/vm, parems: review fixes 2017-05-18 09:05:58 +02:00
Jeffrey Wilcke
e6aff513db core/types: corrected abstract signing address 2017-05-18 09:05:58 +02:00
Jeffrey Wilcke
8a4c1fb799 consensus/ethash: set time to current instead of parent time 2017-05-18 09:05:58 +02:00
Jeffrey Wilcke
10a57fc3d4 consensus, core/*, params: metropolis preparation refactor
This commit is a preparation for the upcoming metropolis hardfork. It
prepares the state, core and vm packages such that integration with
metropolis becomes less of a hassle.

* Difficulty calculation requires header instead of individual
  parameters
* statedb.StartRecord renamed to statedb.Prepare and added Finalise
  method required by metropolis, which removes unwanted accounts from
  the state (i.e. selfdestruct)
* State keeps record of destructed objects (in addition to dirty
  objects)
* core/vm pre-compiles may now return errors
* core/vm pre-compiles gas check now take the full byte slice as argument
  instead of just the size
* core/vm now keeps several hard-fork instruction tables instead of a
  single instruction table and removes the need for hard-fork checks in
  the instructions
* core/vm contains a empty restruction function which is added in
  preparation of metropolis write-only mode operations
* Adds the bn256 curve
* Adds and sets the metropolis chain config block parameters (2^64-1)
2017-05-18 09:05:58 +02:00
Péter Szilágyi
a2f23ca9b1 cmd, core, eth, miner: remove txpool gas price limits (#14442) 2017-05-16 21:07:27 +02:00
Felix Lange
e20158176d les: fix goroutine leak in execQueue (#14480)
execQueue used an atomic counter to track whether the queue had been
closed, but the checking the counter didn't happen because the queue was
blocked on its channel.

Fix it by using a condition variable instead of sync/atomic. I tried an
implementation based on channels first, but it was hard to make it
reliable.

quit now waits for the queue loop to exit.
2017-05-16 20:56:02 +02:00
Péter Szilágyi
ef7b9fb7d0 cmd/puppeth: v4/v5 boot separation, signer gas configs (#14453) 2017-05-13 02:03:56 +02:00
Lewis Marshall
b0d0fafd68 swarm/api: fix error reporting in api.Resolve (#14464)
Previously, resolve errors were being swallowed and the returned error
was a generic "not a content hash" which isn't helpful.

This updates the Resolve function to fail fast rather than only
returning an error at the end, and also adds test coverage.
2017-05-13 02:02:25 +02:00
Péter Szilágyi
90c7155ef4 mobile: accept nil for chainid as homestead signing (#14463) 2017-05-13 02:00:39 +02:00
Koustubh Sinkar
df4e7eccf5 containers/vagrant: add support for CentOS (#14380)
CentOS has been added as a multi-machine option to the Vagrant script.
Ubuntu is still the default option. For starting the CentOS machine, use:

   vagrant up centos
2017-05-13 01:59:03 +02:00
Péter Szilágyi
7c707d14d1 Merge pull request #14454 from karalabe/mobile-surface-txrlp
mobile: add toString & rlp/json encoding for protocol types
2017-05-11 17:53:15 +03:00
Péter Szilágyi
953a995116 mobile: add toString & rlp/json encoding for protocol types 2017-05-11 17:25:40 +03:00
Péter Szilágyi
c5840ce12f Merge pull request #14452 from karalabe/dual-bootnodes
cmd, node: support different bootnodes, fix default light port
2017-05-10 21:00:22 +03:00
Péter Szilágyi
3b3989de6a cmd, node: support different bootnodes, fix default light port 2017-05-10 17:51:52 +03:00
bas-vk
40976ea1a0 README: update attach instructions for testnet users (#14448) 2017-05-09 16:06:07 +02:00
Péter Szilágyi
d18b509e40 Merge pull request #14441 from karalabe/receipt-data-regression
core: fix processing regression during receipt import
2017-05-08 12:37:01 +03:00
Péter Szilágyi
2e4d23a793 Merge pull request #14427 from zsfelfoldi/compress
common/bitutil: added data compression algorithm
2017-05-08 12:30:35 +03:00
Péter Szilágyi
60293820b7 core: fix processing regression during receipt import 2017-05-08 12:09:35 +03:00
Péter Szilágyi
82defe5c56 common/compress: internalize encoders, add length wrappers 2017-05-08 11:38:25 +03:00
Péter Szilágyi
dd483d7d0d Merge pull request #14440 from karalabe/cocoapods-confirm-fix
travis: adapt build script to new travis VM settings
2017-05-08 11:26:35 +03:00
Péter Szilágyi
dddebe469b travis: adapt build script to new travis VM settings 2017-05-08 11:22:08 +03:00
Péter Szilágyi
cf19586cfb common/bitutil: fix decompression corner cases; fuzz, test & bench 2017-05-06 19:06:17 +03:00
Zsolt Felfoldi
fd5d51c9ae common/bitutil: added data compression algorithm 2017-05-05 20:24:48 +02:00
Péter Szilágyi
2ec5cf1673 Merge pull request #14423 from karalabe/bitutil
common/bitutil, consensus/ethash: reusable bitutil package
2017-05-05 18:23:08 +03:00
Péter Szilágyi
36a800a1d2 common/bitutil, consensus/ethash: reusable bitutil package 2017-05-05 16:00:11 +03:00
Péter Szilágyi
93832b633e VERSION, params: begin 1.6.2 release cycle 2017-05-04 14:34:59 +03:00
Péter Szilágyi
021c3c2816 params: release Geth 1.6.1, Deripors of Ohratuu 2017-05-04 14:11:45 +03:00
Péter Szilágyi
ff2c966e7f Merge pull request #14418 from karalabe/rinkeby-flag
cmd, core, params: add --rinkeby flag for fast connectivity
2017-05-04 13:54:02 +03:00
Martin Holst Swende
14cc40a31a Hive-test fixes (#14419)
* core: Fix for consensus test gasLimit > 2^63-1 https://github.com/ethereum/tests/blob/develop/BlockchainTests/bcInvalidHeaderTest.json#L238

* core: fix testcase for uncle gasUsage > gasLimit : https://github.com/ethereum/tests/blob/develop/BlockchainTests/EIP150/bcUncleHeaderValiditiy.json#L986

* math/big: rename TTM63m1 -> MaxBig63, + go fmt

* core: documentation
2017-05-04 13:53:42 +03:00
Péter Szilágyi
881df0e629 Merge pull request #14413 from bas-vk/cli-chain-mngt
Migrate remaining flags/command to new style
2017-05-04 13:31:09 +03:00
Péter Szilágyi
1c2f6f5597 Merge pull request #14402 from karalabe/tiered-faucet
cmd/faucet, cmd/puppeth: support multi-tiered faucet
2017-05-04 13:07:41 +03:00
Péter Szilágyi
d51a9fd6b7 cmd, core, params: add --rinkeby flag for fast connectivity 2017-05-04 12:36:20 +03:00
Péter Szilágyi
464f30d301 cmd/faucet: fix period to days conversion 2017-05-04 11:43:18 +03:00
Péter Szilágyi
8a28408616 cmd/faucet, cmd/puppeth: support multi-tiered faucet 2017-05-04 11:42:43 +03:00
Péter Szilágyi
e1dc7ece62 Merge pull request #14414 from gluk256/77_release
build: wnode added to the build configuration
2017-05-03 16:45:39 +03:00
Vlad
99127ff2e7 build: wnode added to the build configuration 2017-05-03 15:36:02 +02:00
Bas van Kervel
81d6ec908a cmd/geth: migrate dumpconfig command/flags 2017-05-03 14:39:07 +02:00
Bas van Kervel
38b4fc8069 cmd/geth: migrate bug command/flags 2017-05-03 14:33:08 +02:00
Bas van Kervel
11ab73f6d8 cmd/geth: migrate metric command/flags 2017-05-03 14:33:08 +02:00
Bas van Kervel
18e9cb1187 cmd/geth: reorganise misc commands/flags 2017-05-03 14:33:07 +02:00
Bas van Kervel
502a2bd69f cmd/geth: reorganise console/attach commands/flags 2017-05-03 14:33:07 +02:00
Bas van Kervel
8b517d7f00 cmd/geth: reorganise chain commands/flags 2017-05-03 14:33:03 +02:00
Péter Szilágyi
cad071009d Merge pull request #14412 from karalabe/init-both-chains
cmd/geth, cmd/utils: init/removedb on light/full dbs simultaneously
2017-05-03 14:32:24 +03:00
Péter Szilágyi
181a3309df cmd/geth, cmd/utils: init/removedb on light/full dbs simultaneously 2017-05-03 13:35:47 +03:00
Péter Szilágyi
02fa3e3179 Merge pull request #14411 from karalabe/clique-double-sign
consensus/clique: fix overflow on recent signer check around genesis
2017-05-03 11:45:36 +03:00
Péter Szilágyi
a8eafcdc0e Merge pull request #13885 from bas-vk/rpc_generic_pubsub
rpc: support subscriptions under custom namespaces
2017-05-03 11:41:07 +03:00
Péter Szilágyi
bcf2465b0b consensus/clique: fix overflow on recent signer check around genesis 2017-05-03 11:01:06 +03:00
nicky g
c3dc01caf1 README: add config to genesis.json (#14373)
README: add config to genesis.json
2017-05-03 09:10:36 +02:00
Péter Szilágyi
cf4faa491a cmd/puppeth, vendor: update ssh, manage server keys (#14398) 2017-05-03 09:09:34 +02:00
Péter Szilágyi
59966255ad Merge pull request #14407 from karalabe/ethash-generation-race
consensus/ethash: fix a timestamp update race
2017-05-03 09:17:01 +03:00
Péter Szilágyi
f8acc0af7e consensus/ethash: fix a timestamp update race 2017-05-02 16:48:36 +03:00
Péter Szilágyi
02a29060d2 Merge pull request #14406 from karalabe/downloader-sensitive-code
eth/downloader: fix a potential issue against future refactors
2017-05-02 16:31:31 +03:00
Péter Szilágyi
0255ed6335 Merge pull request #14403 from fjl/console-number
console: avoid float64 when remarshaling parameters
2017-05-02 16:24:34 +03:00
Péter Szilágyi
96c2ab22e0 eth/downloader: fix a potential issue against future refactors 2017-05-02 16:14:35 +03:00
Péter Szilágyi
5494e6e7ab Merge pull request #14399 from bas-vk/rpc-cors
rpc: disable CORS if user has not specified a custom config
2017-05-02 15:53:47 +03:00
Felix Lange
32db571681 console: avoid float64 when remarshaling parameters
With Go 1.7, encoding/json marshals float64 using scientific
notation ("10e+6"), but Go's int and *big.Int decoders don't accept such
numbers. This change disables use of float64 to avoid the problem.
2017-05-02 13:42:55 +02:00
Bas van Kervel
a6af56fa4d rpc: disable CORS if user has not specified custom config 2017-05-02 11:14:40 +02:00
Péter Szilágyi
5884606ec3 Merge pull request #14388 from bas-vk/cli-account-mngt
cmd/geth: reorganise account/wallet command/flags
2017-05-02 10:05:20 +03:00
Bas van Kervel
f6c0f76cc5 cmd/geth: reorganise account/wallet command/flags 2017-04-28 14:01:54 +02:00
gluk256
f9be9a2302 whisper: switching to v5 + minor refactoring (#14387) 2017-04-28 11:57:15 +02:00
gluk256
95f0bd0acf whisper: message format refactoring (#14335)
* whisper: salt removed from AES encryption
* whisper: padding format updated
* whisper: padding test added
* whisper: padding refactored, tests fixed
* whisper: padding test updated
* whisper: wnode bugfix
* whisper: send/receive protocol updated
* whisper: minor update
* whisper: bugfix in test
* whisper: updated parameter names and comments
* whisper: functions renamed
* whisper: minor refactoring
2017-04-26 21:05:48 +02:00
Péter Szilágyi
8dce4c283d Merge pull request #14379 from farazdagi/fix/deadlock-in-node-wait
node: fixes deadlock on Wait()
2017-04-25 18:47:55 +03:00
Péter Szilágyi
fff16169c6 Merge pull request #14377 from karalabe/unify-network-ids
cmd, eth, les, mobile: make networkid uint64 everywhere
2017-04-25 18:30:56 +03:00
Victor Farazdagi
5f7eb78918 node: fixes deadlock on Wait() 2017-04-25 18:04:02 +03:00
Péter Szilágyi
e61035c5a3 cmd, eth, les, mobile: make networkid uint64 everywhere 2017-04-25 14:53:50 +03:00
Bas van Kervel
37e3f561f1 rpc: support subscriptions under custom namespaces 2017-04-25 11:13:22 +02:00
Péter Szilágyi
ba3bcd16a6 Merge pull request #14350 from fjl/trie-iterator-skip-2
eth: add debug_storageRangeAt
2017-04-25 11:10:20 +03:00
Felix Lange
207bd7d2cd eth: add debug_storageRangeAt 2017-04-25 02:14:32 +02:00
Felix Lange
4047ccad2f trie: add start key to NodeIterator constructors
The 'step' method is split into two parts, 'peek' and 'push'. peek
returns the next state but doesn't make it current.

The end of iteration was previously tracked by setting 'trie' to nil.
End of iteration is now tracked using the 'iteratorEnd' error, which is
slightly cleaner and requires less code.
2017-04-25 02:14:31 +02:00
Felix Lange
a13e920af0 trie: clean up iterator constructors
Make it so each iterator has exactly one public constructor:

- NodeIterators can be created through a method.
- Iterators can be created through NewIterator on any NodeIterator.
2017-04-25 02:14:31 +02:00
Felix Lange
f958d7d482 trie: rework and document key encoding
'encode' and 'decode' are meaningless because the code deals with three
encodings. Document the encodings and give a name to each one.
2017-04-25 02:14:31 +02:00
Péter Szilágyi
7cc6abeef6 Merge pull request #14372 from bas-vk/bootnodegenkey
cmd/bootnode: stop after generating/writing nodekey
2017-04-24 19:31:23 +03:00
bas-vk
54253aae4c internal/ethapi: return empty arrays instead of null (#14374)
* internal/ethapi: return empty arrays instead of null

* internal/ethapi: minor comments to avoid future regressions
2017-04-24 15:00:30 +03:00
Péter Szilágyi
09aabaea9f Merge pull request #14364 from fjl/core-remove-split-stat-ty
core, light: delete SplitStatTy, ChainSplitEvent (unused)
2017-04-24 11:43:22 +03:00
Bas van Kervel
ecec454e92 cmd/bootnode: stop after generating/writing nodekey 2017-04-24 10:40:20 +02:00
Felix Lange
7b2fc0643f core, light: delete SplitStatTy, ChainSplitEvent (unused) 2017-04-21 18:56:00 +02:00
Péter Szilágyi
d2fda73ad7 Merge pull request #14339 from karalabe/faucet-block-banned-users
cmd/faucet: further user validations and bot protection
2017-04-20 17:42:36 +03:00
Péter Szilágyi
5aa21d8b32 Merge pull request #14357 from karalabe/nousb-flag
cmd, node: add --nousb and node.Config.NoUSB to disable hw wallets
2017-04-20 17:40:57 +03:00
Péter Szilágyi
9fc90b6747 Merge pull request #14358 from karalabe/wrong-genesis-description
core: make genesis incompatibility error more explicit
2017-04-20 15:17:59 +03:00
Péter Szilágyi
edef84da2b core: make genesis incompatibility error more explicit 2017-04-20 14:14:13 +03:00
Péter Szilágyi
6430e672c9 cmd, node: add --nosub and node.Config.NoUSB to disable hw wallets 2017-04-20 14:01:51 +03:00
Felix Lange
a31d268b76 trie: remove Key in MissingNodeError
The key was constructed from nibbles, which isn't possible for all
nodes. Remove the only use of Key in LightTrie by always retrying with
the original key that was looked up.
2017-04-18 14:52:11 +02:00
Péter Szilágyi
e353f9c088 Merge pull request #13886 from bas-vk/rpc_blocknum_parse
rpc: improve BlockNumber unmarshal parsing
2017-04-18 14:55:53 +03:00
Péter Szilágyi
af48a331bf cmd: integrate invisible recaptcha into puppeth 2017-04-16 20:53:27 +03:00
Péter Szilágyi
80e74fc1e0 cmd/faucet: fix websocket double close/reopen 2017-04-16 20:39:42 +03:00
Péter Szilágyi
03dffe3efd cmd/faucet: add optional recaptcha validation support 2017-04-16 19:49:40 +03:00
Péter Szilágyi
cb3f5f8b93 cmd/faucet: double check user against the GH website 2017-04-16 18:49:06 +03:00
Péter Szilágyi
c7a4d9cf8a VERSION, params: begin 1.6.1 release cycle 2017-04-14 13:43:10 +03:00
Péter Szilágyi
facc47cb5c params: release Geth 1.6.0, Puppeth Master 2017-04-14 13:07:07 +03:00
Péter Szilágyi
6876e92f8d Merge remote-tracking branch 'fjl/license-update-1.6' 2017-04-14 12:33:10 +03:00
Péter Szilágyi
15f32a8d57 build: disable misspell, upstream bug prevents builds 2017-04-14 12:24:01 +03:00
Péter Szilágyi
6d359dbcc6 eth: revert accidental ethash cache dir change 2017-04-14 11:35:17 +03:00
Péter Szilágyi
65e1095c3f consensus/ethash: close mmap before rename, windows limitation 2017-04-14 11:32:47 +03:00
Felix Lange
0cc492f815 all: update license information 2017-04-14 10:29:00 +02:00
Péter Szilágyi
ee05cc4a27 Merge pull request #14327 from karalabe/flag-group-fixes
cmd/geth: update flag groups in the geth command usage
2017-04-13 17:28:09 +03:00
Péter Szilágyi
97f38ce4d6 cmd/geth: update flag groups in the geth command usage 2017-04-13 17:12:37 +03:00
Péter Szilágyi
732b75325c Merge pull request #3786 from fjl/compiler-metadata
common/compiler: add metadata output for solc > 0.4.6
2017-04-13 16:26:38 +03:00
Bas van Kervel
7d0ac94809 rpc: improve BlockNumber unmarshal parsing 2017-04-13 13:20:19 +02:00
Péter Szilágyi
906378a32e Merge pull request #14326 from karalabe/launchpad-go-1.8
build: bump launchpad builds to Go 1.8.1
2017-04-13 14:18:53 +03:00
Péter Szilágyi
cc5654cb59 build: bump launchpad builds to Go 1.8.1 2017-04-13 14:11:33 +03:00
Nick Johnson
b35aa21f9f trie: implement unionIterator (#14312) 2017-04-13 11:14:19 +02:00
holisticode
409b61fe3c swarm/api: better name resolver handling (#3754)
Fixes #3608
2017-04-13 11:06:19 +02:00
Péter Szilágyi
d5d910e8b6 Merge pull request #14323 from fjl/ethash-verify-headers-fix
consensus/ethash: simplify concurrency in VerifyHeaders
2017-04-13 10:32:28 +03:00
bas-vk
5e29f4be93 cmd/utils, node: remove unused solc references and improve RPC config (#14324)
Currently http cors and websocket origins are a comma separated string in the
config object. These are replaced with string arrays that are more expressive in
case of a config file.
2017-04-12 23:04:14 +02:00
Felix Lange
b27589517a consensus/ethash: simplify concurrency in VerifyHeaders
This change removes a convoluted use of sync/atomic from VerifyHeaders.
It also fixes the annoying error about future blocks.
2017-04-12 19:38:30 +02:00
Felix Lange
2870496124 core: don't import genesis block in TestDAOForkRangeExtradata
The genesis block doesn't have a valid ancestor.
2017-04-12 18:47:47 +02:00
Péter Szilágyi
43671067fb Merge pull request #14320 from karalabe/rlpdump-single-flag
cmd/rlpdump: support dumping only the first entity
2017-04-12 18:57:37 +03:00
Felix Lange
30d706c35e cmd/geth: add --config file flag (#13875)
* p2p/discover, p2p/discv5: add marshaling methods to Node

* p2p/netutil: make Netlist decodable from TOML

* common/math: encode nil HexOrDecimal256 as 0x0

* cmd/geth: add --config file flag

* cmd/geth: add missing license header

* eth: prettify Config again, fix tests

* eth: use gasprice.Config instead of duplicating its fields

* eth/gasprice: hide nil default from dumpconfig output

* cmd/geth: hide genesis block in dumpconfig output

* node: make tests compile

* console: fix tests

* cmd/geth: make TOML keys look exactly like Go struct fields

* p2p: use discovery by default

This makes the zero Config slightly more useful. It also fixes package
node tests because Node detects reuse of the datadir through the
NodeDatabase.

* cmd/geth: make ethstats URL settable through config file

* cmd/faucet: fix configuration

* cmd/geth: dedup attach tests

* eth: add comment for DefaultConfig

* eth: pass downloader.SyncMode in Config

This removes the FastSync, LightSync flags in favour of a more
general SyncMode flag.

* cmd/utils: remove jitvm flags

* cmd/utils: make mutually exclusive flag error prettier

It now reads:

   Fatal: flags --dev, --testnet can't be used at the same time

* p2p: fix typo

* node: add DefaultConfig, use it for geth

* mobile: add missing NoDiscovery option

* cmd/utils: drop MakeNode

This exposed a couple of places that needed to be updated to use
node.DefaultConfig.

* node: fix typo

* eth: make fast sync the default mode

* cmd/utils: remove IPCApiFlag (unused)

* node: remove default IPC path

Set it in the frontends instead.

* cmd/geth: add --syncmode

* cmd/utils: make --ipcdisable and --ipcpath mutually exclusive

* cmd/utils: don't enable WS, HTTP when setting addr

* cmd/utils: fix --identity
2017-04-12 17:27:23 +03:00
Péter Szilágyi
b57680b0b2 Merge pull request #14322 from karalabe/puppeth-new-configs
cmd/puppeth: format dashboard html, update syncmode flags
2017-04-12 17:26:57 +03:00
Péter Szilágyi
e418bc67d2 cmd/puppeth: format dashboard html, update syncmode flags 2017-04-12 17:07:34 +03:00
Péter Szilágyi
a7b9e484d0 consensus, core, ethstats: use engine specific block beneficiary (#14318)
* consensus, core, ethstats: use engine specific block beneficiary

* core, eth, les, miner: use explicit beneficiary during mining
2017-04-12 16:38:31 +03:00
Péter Szilágyi
6b7ae4e751 consensus/clique, internal/web3ext: support hash based API queries (#14321)
* consensus/clique, internal/web3ext: support hash based API queries

* consensus/clique: make RPC return types public
2017-04-12 15:37:10 +03:00
Péter Szilágyi
436acb4f75 cmd/rlpdump: support dumping only the first entity 2017-04-12 14:27:34 +03:00
Nick Johnson
050ceff1ae Merge pull request #14311 from Arachnid/tracing
internal/ethapi: Add support for fetching information about the current call in JS traces
2017-04-12 08:56:27 +01:00
Péter Szilágyi
a0cd77e833 build: create deb source for Ubuntu Zesty (#14316) 2017-04-12 02:07:00 +02:00
Zahoor Mohamed
1d1d988aa7 swarm/api: FUSE read-write support (#13872)
- Moved fuse related code in a new package, swarm/fuse
- Added write support
  - Create new files
  - Delete existing files
  - Append to files (with limitations)
- More test coverage
2017-04-12 02:06:02 +02:00
Victor Farazdagi
dd37064a15 cmd/swarm: add --password (#3748) 2017-04-12 02:03:42 +02:00
Nick Johnson
49f1e84253 internal/ethapi: Add support for fetching information about the current call in JS traces 2017-04-11 11:37:23 +01:00
Jamie Pitts
9de257505b params: updated testnet bootnodes (#14310) 2017-04-11 11:57:54 +02:00
Péter Szilágyi
706a1e552c cmd/puppeth: your Ethereum private network manager (#13854) 2017-04-11 01:25:53 +02:00
Felföldi Zsolt
18bbe12425 les: allow LES connection to other servers (#13889) 2017-04-11 01:23:39 +02:00
Péter Szilágyi
04fcae207d p2p: if no nodes are connected, attempt dialing bootnodes (#13874) 2017-04-10 18:33:41 +02:00
Justin
542e42b21e core: fix comment typo 2017-04-10 16:01:31 +03:00
Péter Szilágyi
feeccdf4ec consensus/clique: Proof of Authority (#3753)
This PR is a prototype implementation of plugable consensus engines and the
Clique PoA protocol ethereum/EIPs#225
2017-04-10 12:24:12 +02:00
Péter Szilágyi
bfe5eb7f8c eth: accept transactions when starting CPU mining (#13882) 2017-04-10 10:43:01 +02:00
Péter Szilágyi
f32b72ca5d Merge pull request #13883 from karalabe/boardcast-sync-head
eth: announce block after sync cycle (star topology)
2017-04-10 09:03:00 +03:00
gluk256
9cd7135516 whisper: big refactoring (#13852)
* whisper: GetMessages fixed; size restriction updated
* whisper: made PoW and MaxMsgSize customizable
* whisper: test added
* whisper: sym key management changed
* whisper: identity management refactored
* whisper: API refactoring (Post and Filter)
* whisper: big refactoring complete
* whisper: spelling fix
* whisper: variable topic size allowed for a filter
* whisper: final update
* whisper: formatting
* whisper: file exchange introduced in wnode
* whisper: bugfix
* whisper: API updated + new tests
* whisper: statistics updated
* whisper: wnode server updated
* whisper: allowed filtering for variable topic size
* whisper: tests added
* whisper: resolving merge conflicts
* whisper: refactoring (documenting mostly)
* whsiper: tests fixed
* whisper: down cased error messages
* whisper: documenting the API functions
* whisper: logging fixed
* whisper: fixed wnode parameters
* whisper: logs fixed (typos)
2017-04-09 23:49:22 +02:00
Péter Szilágyi
bd2c54fa9f eth: announce block after sync cycle (star topology) 2017-04-09 20:12:46 +03:00
Péter Szilágyi
8570ef19eb Merge pull request #13881 from karalabe/go-1.8.1
travis, appveyor: update to Go 1.8.1
2017-04-08 22:35:41 +03:00
Péter Szilágyi
d144299af4 travis, appveyor: update to Go 1.8.1 2017-04-08 22:20:15 +03:00
Péter Szilágyi
badbaf66b6 Merge pull request #13880 from karalabe/remote-miner-fix
consensus/ethash, eth: don't mine if 0 threads are set
2017-04-08 20:40:54 +03:00
Péter Szilágyi
b801be99d4 consensus, eth: don't CPU mine by default during remote mining 2017-04-07 17:22:06 +03:00
Péter Szilágyi
cc13d576f0 Merge pull request #13870 from karalabe/miners-fixes
all: clean up various error handling in core and the miner
2017-04-07 11:03:11 +03:00
Lewis Marshall
71fdaa4238 swarm/api: refactor and improve HTTP API (#3773)
This PR deprecates the file related RPC calls in favour of an improved HTTP API.

The main aim is to expose a simple to use API which can be consumed by thin
clients (e.g. curl and HTML forms) without the need for complex logic (e.g.
manipulating prefix trie manifests).
2017-04-07 00:22:22 +02:00
Péter Szilágyi
158d603528 consensus, core: drop all the legacy custom core error types 2017-04-06 17:34:19 +03:00
Felföldi Zsolt
9aca9e6deb cmd, les, eth, eth/gasprice: using new gas price oracle (#13853)
* cmd, les, eth, eth/gasprice: using new gas price oracle

* eth/gasprice: renamed source file

* eth/gasprice: added security checks for gpo params

* eth/gasprice: fixed naming issues

* eth/gasprice: max limit, maxEmpty
2017-04-06 17:20:42 +03:00
Louis Holbrook
0ec1104ba9 cmd/swarm: allow uploading from stdin (#3744)
- intended to be a swarm alternative to termbin.com
- added --stdin flag to swarm executable. if set, swarm will
  read data from stdin and postRaw it.
2017-04-06 14:21:16 +02:00
Péter Szilágyi
702bef8493 cmd/geth, eth: drop bad block reporting, its offline anyway 2017-04-06 14:25:05 +03:00
Péter Szilágyi
c76ad94492 .travis, build: autodelete old unstable archives (#13867)
This commit adds a build step to travis to auto-delete unstable archives older than
14 days (our regular release schedule) from Azure via ci.go purge.

The commit also pulls in the latest Azure storage code, also switching over from
the old import path (github.com/Azure/azure-sdk-for-go) to the new split one
(github.com/Azure/azure-storage-go).
2017-04-06 12:53:33 +02:00
Péter Szilágyi
d83a9a8f44 miner: don't verify our own blocks, trust the engine 2017-04-06 12:22:14 +03:00
Felix Lange
3d8de95f99 core, core/types: regenerate JSON marshaling, add "hash" to headers (#13868)
* Makefile: fix devtools target

* core: regenerate genesis marshaling with fjl/gencodec@cbfa5be5a8

* core/types: regenerate marshaling methods with fjl/gencodec@cbfa5be5a8

* core/types: add "hash" to JSON headers
2017-04-06 11:38:21 +03:00
Péter Szilágyi
24b9860c1b cmd/geth, node: surface geth architecture into version (#13866) 2017-04-05 21:51:01 +02:00
Martin Holst Swende
cc303017c3 debug: convert uint64-blocknumber into rpc.Blocknumber (#13862)
* debug: Converted uint64-blocknumber into rpc.Blocknumber

* api/debug: Fix pending block issues in DumpBlock
2017-04-05 17:49:54 +02:00
gary rong
49437a02c9 core/state: make TestSnapshotRandom work again (#3816)
In `touch` operation, only `touched` filed has been changed. Therefore
in the related undo function, only `touched` field should be reverted.
In addition, whether remove this obj from dirty map should depend on
prevDirty flag.
2017-04-05 00:44:16 +02:00
Lewis Marshall
b319f027a0 cmd/swarm, swarm/api/client: add HTTP API client and 'swarm ls' command (#3742)
This adds a swarm ls command which lists files and directories stored in a
manifest. Rather than listing all files, it uses "directory prefixes" in case there are a
lot of files in a manifest but you just want to traverse it.

This also includes some refactoring to the tests and the introduction of a
swarm/api/client package to make things easier to test.
2017-04-05 00:20:07 +02:00
Péter Szilágyi
09777952ee core, consensus: pluggable consensus engines (#3817)
This commit adds pluggable consensus engines to go-ethereum. In short, it
introduces a generic consensus interface, and refactors the entire codebase to
use this interface.
2017-04-05 00:16:29 +02:00
Péter Szilágyi
e50a5b7771 Merge pull request #13856 from karalabe/ethstats-sanity-checks
ethstats: sanity check ethstats history queries
2017-04-04 13:03:34 +03:00
Péter Szilágyi
fb98a8c6c2 ethstats: cut short unavailable history responses 2017-04-04 11:41:17 +03:00
Péter Szilágyi
96d1a4aee6 ethstats: sanity check ethstats history queries 2017-03-31 15:06:54 +03:00
Felix Lange
105b37f1b4 swarm/api: improve FUSE build constraints, logging and APIs (#3818)
* swarm/api: fix build/tests on unsupported platforms

Skip FUSE tests if FUSE is unavailable and change build constraints so
the 'lesser' platforms aren't mentioned explicitly. The test are
compiled on all platforms to prevent regressions in _fallback.go

Also gofmt -w -s because why not.

* internal/web3ext: fix swarmfs wrappers

Remove inputFormatter specifications so users get an error
when passing the wrong number of arguments.

* swarm/api: improve FUSE-related logging and APIs

The API now returns JSON objects instead of strings.
Log messages for invalid arguments are removed.
2017-03-31 12:11:01 +02:00
Péter Szilágyi
c4a0efafd7 Merge pull request #13851 from karalabe/ethstats-url-scheme-discovery
ethstats: work around weird URL scheme parsing issues
2017-03-30 13:25:17 +03:00
Péter Szilágyi
db93641941 ethstats: work around weird URL scheme parsing issues 2017-03-30 12:53:50 +03:00
Felix Lange
1cf2ee4597 build: work around cgo linker issue on macOS 10.12.4 (#13849)
Fixes #3792 by stripping debug symbols.
2017-03-29 12:20:57 +02:00
bas-vk
baf20010e7 core/types: rename txdata.gasLimit -> txdata.gas in JSON (#13848) 2017-03-29 11:59:13 +02:00
Péter Szilágyi
16afb5c468 Merge pull request #13516 from fjl/core-marshal-non-pointer
core, core/types: use non-pointer receiver for Marshal* methods
2017-03-28 15:55:34 +03:00
Péter Szilágyi
225c28716f Merge pull request #3801 from karalabe/ledger-linux-confirm
accounts/usbwallet: fix Ledger hidapi/libusb protocol violation
2017-03-28 09:16:23 +03:00
Felix Lange
aa9a78e463 core, core/types: use non-pointer receiver for Marshal* methods
Regenerated with fjl/gencodec@1a75a21610
Also add ,omitempty to optional GenesisAccount fields.
2017-03-27 13:29:01 +02:00
Péter Szilágyi
7419d0c382 Merge pull request #3820 from fjl/core-types-eip155-chainid-mul
core/types: ensure all EIP155 signer fields are set by deriveSigner
2017-03-27 00:22:34 +03:00
Felix Lange
4be37e91b9 core/types: ensure all EIP155 signer fields are set by deriveSigner
Fixes #3819
2017-03-24 22:06:10 +01:00
Péter Szilágyi
1018bf6a00 rpc: honour pending requests before tearing conn down (#3814) 2017-03-24 12:07:12 +01:00
Péter Szilágyi
37e252587a Merge pull request #3813 from fjl/build-fixes-2
build: unify vendor skipping, always run go vet
2017-03-24 11:52:42 +02:00
Péter Szilágyi
bb7dca275c ethstats: cleanups, trace logs and "fix" history responses (#3812) 2017-03-24 10:42:40 +01:00
Felix Lange
69ac6cc70e travis.yml: re-add missing build commands for Go 1.7 2017-03-24 10:29:20 +01:00
Felix Lange
df1fbe3c06 build: always run go vet
This ensures 'make test' finds all errors that remote CI would find.
Go 1.7 vet reports a false positive in package log, add a workaround.
2017-03-24 10:28:46 +01:00
Péter Szilágyi
8771c3061f Merge pull request #3794 from fjl/core-genesis-refactor
core: refactor genesis handling
2017-03-23 17:36:38 +02:00
Péter Szilágyi
8ff7e55ab5 accounts/usbwallet: if a confirmation is pending, skip refresh 2017-03-23 17:04:39 +02:00
Felix Lange
37dd9086ec core: refactor genesis handling
This commit solves several issues concerning the genesis block:

* Genesis/ChainConfig loading was handled by cmd/geth code. This left
  library users in the cold. They could specify a JSON-encoded
  string and overwrite the config, but didn't get any of the additional
  checks performed by geth.
* Decoding and writing of genesis JSON was conflated in
  WriteGenesisBlock. This made it a lot harder to embed the genesis
  block into the forthcoming config file loader. This commit changes
  things so there is a single Genesis type that represents genesis
  blocks. All uses of Write*Genesis* are changed to use the new type
  instead.
* If the chain config supplied by the user was incompatible with the
  current chain (i.e. the chain had already advanced beyond a scheduled
  fork), it got overwritten. This is not an issue in practice because
  previous forks have always had the highest total difficulty. It might
  matter in the future though. The new code reverts the local chain to
  the point of the fork when upgrading configuration.

The change to genesis block data removes compression library
dependencies from package core.
2017-03-23 15:58:43 +01:00
Felix Lange
67c47459f2 core/types: handle nil ChainId in NewEIP155Signer
All uses of ChainConfig.ChainId eventually end up in NewEIP155Signer.
This fixes the case where users forget to set the ChainId in their
config.
2017-03-23 15:58:42 +01:00
Felix Lange
0f4b75bea2 core/state: expose CommitTo 2017-03-23 15:58:42 +01:00
Felix Lange
d42a56afc5 common: add UnprefixedHash, UnprefixedAddress 2017-03-23 15:58:42 +01:00
Felix Lange
b4547a560b common/hexutil: add UnmarshalFixedUnprefixedText 2017-03-23 15:58:42 +01:00
Felix Lange
04fa6a3744 common/math: add HexOrDecimal64, HexOrDecimal256 2017-03-23 15:58:42 +01:00
Péter Szilágyi
26da6daaa9 accounts/usbwallet: fix Ledger hidapi/libusb protocol violation 2017-03-23 16:51:04 +02:00
Felix Lange
e7911ad9ea build: unify vendor skipping logic
This fixes a recent bug where 'make geth' built everything instead of
just geth.
2017-03-23 15:50:05 +01:00
Zahoor Mohamed
11e7a712f4 swarm/api: support mounting manifests via FUSE (#3690) 2017-03-23 14:56:06 +01:00
Péter Szilágyi
61d2150a07 Merge pull request #3795 from fjl/pow-fix-test-mode
pow: fix Search with ethash test mode
2017-03-23 10:56:12 +02:00
Péter Szilágyi
3fa0fa713b Merge pull request #3809 from fjl/all-use-normal-context
all: import "context" instead of "golang.org/x/net/context"
2017-03-23 10:22:56 +02:00
Felix Lange
f1534f5797 trie, whisper/whisperv5: use math/rand Read function 2017-03-22 20:49:15 +01:00
Felix Lange
9a2720fb35 mobile: remove support for Go < 1.7 2017-03-22 20:49:15 +01:00
Felix Lange
c213fd1fd8 all: import "context" instead of "golang.org/x/net/context"
There is no need to depend on the old context package now that the
minimum Go version is 1.7. The move to "context" eliminates our weird
vendoring setup. Some vendored code still uses golang.org/x/net/context
and it is now vendored in the normal way.

This change triggered new vet checks around context.WithTimeout which
didn't fire with golang.org/x/net/context.
2017-03-22 20:49:15 +01:00
Felföldi Zsolt
525116dbff les: implement request distributor, fix blocking issues (#3660)
* les: implement request distributor, fix blocking issues
* core: moved header validation before chain mutex lock
2017-03-22 20:44:22 +01:00
Péter Szilágyi
1c1dc0e0fc Merge pull request #3808 from fjl/build-go-1.7
build: require Go >= 1.7
2017-03-22 18:49:50 +02:00
Felix Lange
c6e6f1fec2 build: remove support for the GO_OPENCL environment variable
We don't use the opencl build tag anymore.
2017-03-22 16:00:21 +01:00
Felix Lange
da7af44060 build: require Go >= 1.7
We have decided to bump the requirement to Go 1.7 because it enables
subtests and allows dropping backwards-compatibility code. This is in
line with Go's support policy. Go 1.6 and earlier no longer receive
security updates.
2017-03-22 16:00:16 +01:00
Yohann Leon
6742fc526f core/vm: use uint64 instead of *big.Int in tracer (#3805) 2017-03-22 15:32:51 +01:00
Péter Szilágyi
9b84caf3a5 core, eth, les: support resuming fast sync on heavy rollback (#3743) 2017-03-22 01:37:24 +01:00
Felix Lange
06d6685eb5 Merge pull request #3756 from fjl/core-types-gencodec
core/types: use gencodec for JSON marshaling code
2017-03-22 01:36:22 +01:00
Péter Szilágyi
1dfd65f6d0 Merge pull request #3802 from karalabe/cocoapods-stable
travis: switch to cocoapods 1.2.0 stable
2017-03-20 14:35:48 +02:00
Péter Szilágyi
7242e4f71b travis: switch to cocoapods 1.2.0 stable 2017-03-20 14:12:47 +02:00
Péter Szilágyi
be39bf382a Merge pull request #3800 from karalabe/ethstats-genesis-fixes
ethstats: try both ws:// and wss:// if none specified
2017-03-20 13:04:57 +02:00
Péter Szilágyi
2ba9374789 ethstats: try both ws:// and wss:// if none specified 2017-03-20 12:45:43 +02:00
holisticode
d97dea51ec swarm/network/kademlia: set kademlia log output to debug instead of warn (#3787) 2017-03-18 01:45:00 +01:00
Felix Lange
24dd0355a3 pow: fix Search with ethash test mode
The cache/dataset methods crashed with a nil pointer error if
cachesinmem/dagsinmem were zero. Fix it by skipping the eviction logic
if there are no caches/datasets.

Search always used the regular dataset size regardless of test mode. Fix
it by removing the redundant size parameter of hashimotoFull.

Fixes #3784
2017-03-18 01:05:28 +01:00
bas-vk
6d038e762b accounts/abi/bind: allow client to specify sender address for call (#3782) 2017-03-16 12:24:22 +01:00
Steve Waldman
728a299728 common/compiler: add metadata output for solc > 0.4.6
Metadata is provided as JSON string, rather than as JSON object. This
ensures that we can decode to a set of bytes that will be consistent
with the swarm hash embedded in the code, without worrying about
ambiguities of spacing, ordering, or escaping.
2017-03-16 12:18:38 +01:00
Micah Zoltu
4e4e5fca54 rpc: add support for extended headers in CORS requests (#3783)
Fixes #3762.  Details about parameter:
a62a804a8a/cors.go (L50-L54)
2017-03-16 04:34:08 +01:00
Péter Szilágyi
61ede86737 internal/ethapi: drop eth_compile (#3740) 2017-03-16 02:54:52 +01:00
Péter Szilágyi
dc4c59d42b Merge pull request #3779 from zsfelfoldi/cht-update
light: added new CHT
2017-03-14 17:02:56 +02:00
Zsolt Felfoldi
0a01f3f607 light: added new CHT 2017-03-14 16:59:42 +02:00
Péter Szilágyi
f3579f6460 pow: make data dumps backwards compatible, fix DAG end 2017-03-09 15:50:14 +01:00
Péter Szilágyi
5c8fa6ae1a crypto, pow, vendor: hash optimizations, mmap ethash 2017-03-09 15:50:14 +01:00
Péter Szilágyi
b7d93500f1 all: finish integrating Go ethash, delete C++ vendor 2017-03-09 15:50:14 +01:00
Péter Szilágyi
df72e20cc5 pow: only support prime calculations on Go 1.8 and above 2017-03-09 15:50:14 +01:00
Péter Szilágyi
023670f6ba cmd, eth, les, node, pow: disk caching and progress reports 2017-03-09 15:50:14 +01:00
Péter Szilágyi
567d41d936 all: swap out the C++ ethash to the pure Go one (mining todo) 2017-03-09 15:50:14 +01:00
Péter Szilágyi
3b00a77de5 crypto, pow: add pure Go implementation of ethash 2017-03-09 15:50:14 +01:00
Péter Szilágyi
288700c4d8 build: add bootnode to Ubuntu PPAs too (#3766) 2017-03-09 11:02:43 +01:00
Martin Holst Swende
544247c918 * cmd/geth: add --nocompaction flag + multiple import files
* main,import: Add --nocompaction flag + multiple import files

* geth/import: documentation

* import: Added more info to err message

* fix :P
2017-03-08 13:26:19 +02:00
Felix Lange
8cf08e4b25 core/types: use gencodec for JSON marshaling code 2017-03-07 12:45:12 +01:00
Felix Lange
eee96a5bb7 rlp: add support for "-" struct tag 2017-03-07 12:45:12 +01:00
Felix Lange
667cd518ce internal/jsre/deps: ensure that go generate produces no changes 2017-03-07 12:38:46 +01:00
Péter Szilágyi
4c6f4e569e Merge pull request #3755 from ligi/mobile_fix_typo
mobile: Fix typo ( Ethereun -> Ethereum )
2017-03-07 02:35:11 +02:00
Felix Lange
9c4fd4e9c9 Makefile: add devtools target 2017-03-07 01:33:05 +01:00
ligi
db2698c87c mobile: Fix typo ( Ethereun -> Ethereum ) 2017-03-07 01:30:06 +01:00
Péter Szilágyi
07c216d603 Merge pull request #3739 from karalabe/logger-updates-4
all: update light logs (and a few others) to the new model
2017-03-03 18:53:30 +02:00
Péter Szilágyi
1a00e39539 Merge pull request #3738 from karalabe/impossible-reorg-warning
core: reorg logs crashed, add a check for corner cases
2017-03-03 14:37:02 +02:00
Péter Szilágyi
92e50adfa3 Merge pull request #3741 from karalabe/fix-makefile-xgo
build: fix xgo argument order when building from make
2017-03-03 14:36:21 +02:00
Péter Szilágyi
2b284e7366 build: fix xgo argument order when building from make 2017-03-03 12:18:44 +02:00
Péter Szilágyi
e7030c4bf5 all: update light logs (and a few others) to the new model 2017-03-03 11:41:52 +02:00
Péter Szilágyi
a38e1a9c00 core: reorg logs crashed, add a check for corner cases 2017-03-03 09:54:13 +02:00
Aaron Hnatiw
faf713632c README: fix typo 2017-03-02 18:44:07 +02:00
Péter Szilágyi
725c2646a0 Merge pull request #3735 from karalabe/bundle-bootnode
build: bundle the bootnode too into alltools
2017-03-02 16:05:23 +02:00
Péter Szilágyi
f2e94ff94b Merge pull request #3727 from karalabe/travis-mips
travis: support building mips32 and mips64 too
2017-03-02 15:49:40 +02:00
Péter Szilágyi
090699c0f6 build: bundle the bootnode too into alltools 2017-03-02 15:23:15 +02:00
Péter Szilágyi
213b8f9af4 Merge pull request #3722 from fjl/hexutil-text-unmarshal
common/hexutil: implement TextMarshaler, TextUnmarshaler
2017-03-02 15:16:59 +02:00
Péter Szilágyi
9184249b39 Logger updates 3 (#3730)
* accounts, cmd, eth, ethdb: port logs over to new system

* ethdb: drop concept of cache distribution between dbs

* eth: fix some log nitpicks to make them nicer
2017-03-02 14:06:16 +01:00
Felix Lange
280f08be84 common/hexutil: ensure negative big.Int is encoded sensibly
Restricting encoding is silly.
2017-03-02 14:05:46 +01:00
Felix Lange
d304da3803 common/hexutil: implement TextMarshaler, TextUnmarshaler
This commit makes the wrapper types more generally applicable.
encoding.TextMarshaler is supported by most codec implementations (e.g.
for yaml).

The tests now ensure that package json actually recognizes the custom
marshaler implementation irrespective of how it is implemented.

The Uint type has new tests, too. These are tricky because uint size
depends on the CPU word size. Turns out that there was one incorrect
case where decoding returned ErrUint64Range instead of ErrUintRange.
2017-03-02 14:05:46 +01:00
Felix Lange
357d00cdb1 common/hexutil: don't leak encoding/hex errors in Decode
All other functions return errors from package hexutil, ensure that
Decode does too.
2017-03-02 14:05:46 +01:00
Felix Lange
f3b7dcc5bd common/hexutil: reject big integer inputs > 256 bits
This follows the change to common/math big integer parsing in PR #3699.
2017-03-02 14:05:46 +01:00
Péter Szilágyi
82e7c1d124 Merge pull request #3728 from obscuren/format-trace
core/evm, core/vm: improved evm trace output
2017-03-02 13:01:01 +02:00
Péter Szilágyi
f972691eea travis: support building mips32 and mips64 too 2017-03-02 11:43:06 +02:00
Valentin Wüstholz
c52ab932e6 cmd/disasm, cmd/evm: integrate disasm tool into evm tool. (#3729) 2017-03-01 13:34:50 +01:00
Jeffrey Wilcke
f30733c806 cmd/evm: removed -sysstat and moved content to -debug flag
Added the ability to directly compile and run ethereum assembly using
the evm utility: `evm run <file>`. This is equivalant to `evm compile
<file> | evm run`.
2017-03-01 11:52:57 +01:00
Jeffrey Wilcke
bf4155846c core/evm, core/vm: improved evm trace output
* Improved the standard evm tracer output and renamed it to WriteTrace
which now takes an io.Writer to write the logs to.
* Added WriteLogs which writes logs to the given writer in a readable
format.
* evm utility now also prints logs generated during the execution.
2017-03-01 11:20:25 +01:00
Jeffrey Wilcke
230cf2ec91 cmd/evm, core/asm: add EVM assembler (#3686)
The evm compile command implements a simple assembly language that compiles to
EVM bytecode.
2017-03-01 01:11:24 +01:00
Jeffrey Wilcke
7ff75ac2f2 cmd/utils, core, params: fork all teh things for dev mode (#3697) 2017-02-28 23:18:13 +01:00
Péter Szilágyi
167be7f260 Merge pull request #3725 from karalabe/kill-it-with-fire
errs: kill it with fire
2017-02-28 18:45:44 +02:00
Péter Szilágyi
7e3762fdc6 errs: kill it with fire 2017-02-28 18:01:54 +02:00
Péter Szilágyi
94c71c171f Merge pull request #3723 from karalabe/logger-updates-2
Logger updates
2017-02-28 16:55:37 +02:00
Felix Lange
5f7826270c all: unify big.Int zero checks, use common/math in more places (#3716)
* common/math: optimize PaddedBigBytes, use it more

name              old time/op    new time/op    delta
PaddedBigBytes-8    71.1ns ± 5%    46.1ns ± 1%  -35.15%  (p=0.000 n=20+19)

name              old alloc/op   new alloc/op   delta
PaddedBigBytes-8     48.0B ± 0%     32.0B ± 0%  -33.33%  (p=0.000 n=20+20)

* all: unify big.Int zero checks

Various checks were in use. This commit replaces them all with Int.Sign,
which is cheaper and less code.

eg templates:

    func before(x *big.Int) bool { return x.BitLen() == 0 }
    func after(x *big.Int) bool  { return x.Sign() == 0 }

    func before(x *big.Int) bool { return x.BitLen() > 0 }
    func after(x *big.Int) bool  { return x.Sign() != 0 }

    func before(x *big.Int) int { return x.Cmp(common.Big0) }
    func after(x *big.Int) int  { return x.Sign() }

* common/math, crypto/secp256k1: make ReadBits public in package math
2017-02-28 15:09:11 +01:00
Péter Szilágyi
b117da2db3 core/state: drop most of a logs (useless at this volume) 2017-02-28 15:51:30 +02:00
Péter Szilágyi
e02883c0a2 core, log: track field length and pad to align 2017-02-28 15:36:51 +02:00
Péter Szilágyi
e588e0ca2b all: next batch of log polishes to contextual versions 2017-02-28 15:03:20 +02:00
Péter Szilágyi
d4f60d362b Merge pull request #3721 from karalabe/drop-legacy-db-updates
core, eth: drop database block splitting upgrader
2017-02-28 14:00:25 +02:00
Péter Szilágyi
46bcd9a92c core, eth: drop database block splitting upgrader 2017-02-28 13:41:02 +02:00
Jamie Pitts
dbd88a1aa4 params: updated bootnodes (#3720)
* Updated the list of go bootnodes: replaced BR with a new one, added US-WEST and AU.

* Updated bootnodes, minor go formatting change.
2017-02-28 12:30:44 +02:00
Péter Szilágyi
965407f238 Merge pull request #3709 from fjl/p2p-context-log
p2p, p2p/discover, p2p/nat: rework logging using context keys
2017-02-28 12:22:05 +02:00
Felix Lange
96ae35e2ac p2p, p2p/discover, p2p/nat: rework logging using context keys 2017-02-28 10:20:29 +01:00
Péter Szilágyi
dc0a006c7c Merge pull request #3718 from karalabe/terminal-format-hash
common, eth/downloader, log: support terminal log formatting
2017-02-27 20:49:17 +02:00
Péter Szilágyi
2f28a12cdb common, eth/downloader, log: support terminal log formatting 2017-02-27 19:15:18 +02:00
Felix Lange
35e8308bf7 eth, les: shorten genesis block mismatch error message 2017-02-27 17:19:41 +01:00
Péter Szilágyi
fc97c7a38d Merge pull request #3717 from tranvictor/master
internal/ethapi: return logsBloom for pending block
2017-02-27 18:11:11 +02:00
Péter Szilágyi
48bc07ae97 Merge pull request #3708 from fjl/log-letter
log: fix annoyances
2017-02-27 18:05:50 +02:00
tranvictor
a624ce69f7 internal/ethapi: fixes #2648, returns logsBloom for pending block 2017-02-27 21:45:57 +07:00
Felix Lange
d0eba23af3 all: disable log message colors outside of geth
Also tweak behaviour so colors are only enabled when stderr is a terminal.
2017-02-27 15:33:12 +01:00
Felix Lange
43362ab4fb log: disable logs by default 2017-02-27 15:32:48 +01:00
Felix Lange
38e273597c log: log full level names instead of mispelled "EROR", "DBUG" 2017-02-27 15:32:48 +01:00
Péter Szilágyi
e8b3e22612 Merge pull request #3711 from karalabe/update-downloader-logs
eth/downloader: port over old logs from glog to log15
2017-02-27 14:18:26 +02:00
Péter Szilágyi
32ee1b3cd8 Merge pull request #3715 from karalabe/update-hid-library
vendor: update HID library for glibc < v2.17 build
2017-02-27 14:04:40 +02:00
Péter Szilágyi
8676aeb798 eth/downloader: review fixes 2017-02-27 13:22:33 +02:00
Valentin Wüstholz
37511ec520 core, core/vm, cmd/disasm: unify procedures for disassembling evm code (#3530) 2017-02-27 12:21:19 +01:00
Péter Szilágyi
46eea4d105 accounts, eth/downloader: use "err" instead of "error" in logs 2017-02-27 13:17:58 +02:00
Péter Szilágyi
0a63c3e362 eth/downloader: port over old logs from glog to log15 2017-02-27 13:16:40 +02:00
Péter Szilágyi
45c7cfd2e6 vendor: update HID library for glibc < v2.17 build 2017-02-27 12:58:09 +02:00
Felix Lange
5c8fe28b72 common: move big integer math to common/math (#3699)
* common: remove CurrencyToString

Move denomination values to params instead.

* common: delete dead code

* common: move big integer operations to common/math

This commit consolidates all big integer operations into common/math and
adds tests and documentation.

There should be no change in semantics for BigPow, BigMin, BigMax, S256,
U256, Exp and their behaviour is now locked in by tests.

The BigD, BytesToBig and Bytes2Big functions don't provide additional
value, all uses are replaced by new(big.Int).SetBytes().

BigToBytes is now called PaddedBigBytes, its minimum output size
parameter is now specified as the number of bytes instead of bits. The
single use of this function is in the EVM's MSTORE instruction.

Big and String2Big are replaced by ParseBig, which is slightly stricter.
It previously accepted leading zeros for hexadecimal inputs but treated
decimal inputs as octal if a leading zero digit was present.

ParseUint64 is used in places where String2Big was used to decode a
uint64.

The new functions MustParseBig and MustParseUint64 are now used in many
places where parsing errors were previously ignored.

* common: delete unused big integer variables

* accounts/abi: replace uses of BytesToBig with use of encoding/binary

* common: remove BytesToBig

* common: remove Bytes2Big

* common: remove BigTrue

* cmd/utils: add BigFlag and use it for error-checked integer flags

While here, remove environment variable processing for DirectoryFlag
because we don't use it.

* core: add missing error checks in genesis block parser

* common: remove String2Big

* cmd/evm: use utils.BigFlag

* common/math: check for 256 bit overflow in ParseBig

This is supposed to prevent silent overflow/truncation of values in the
genesis block JSON. Without this check, a genesis block that set a
balance larger than 256 bits would lead to weird behaviour in the VM.

* cmd/utils: fixup import
2017-02-26 22:21:51 +01:00
Péter Szilágyi
50ee279f25 Merge pull request #3705 from karalabe/drop-legacy-commands
Drop legacy commands
2017-02-24 13:59:56 +02:00
gluk256
562ccff822 whisper: fixed temporary directory for tests (#3707) 2017-02-24 09:21:01 +01:00
gluk256
11539030cd whisper: expiry refactoring (#3706) 2017-02-23 18:46:32 +01:00
Péter Szilágyi
aca066f337 cmd/geth: drop upgradedb subcommand since it's unfeasible
This command was meant as a hackish way to upgrade our chain database way back
when nobody cared for live updates and the size of the database along with its
import times was small. With the current database weighing hundreds of GBs and
processing times of many days, this command is just ludicrous.
2017-02-23 16:49:50 +02:00
Péter Szilágyi
5ee00209d2 cmd/ethtest: drop the manual test tool in favor of hive
All the state and block tests are ran as part of our CU builds internally, as
well as have been added to hive black-box tests. As such, there is no reason for
maintaining an extra standalone tool.
2017-02-23 16:49:50 +02:00
Péter Szilágyi
e7bdb00700 cmd/gethrpctest: ethereum/rpc-tests is deprecated
Only ethereum/rpc-tests used this command, which hasn't been maintained for over
a year now, a lot of tests failing. What's left of it was moved underneath hive,
which can run the entire test against a black-box geth without special commands.

Also a new RPC test suite is being added which is also based on black box tests,
not needing special commands any more.
2017-02-23 16:49:49 +02:00
Péter Szilágyi
357732a840 Merge pull request #3696 from karalabe/contextual-logger
Contextual logger
2017-02-23 16:49:05 +02:00
Péter Szilágyi
f89dd62776 internal, log: support debug log prints, displaying log origins 2017-02-23 12:16:47 +02:00
Péter Szilágyi
1ca20a2697 cmd, whisper/mailserver: revert to utils.Fatalf 2017-02-23 12:16:46 +02:00
Péter Szilágyi
23a5d64fd0 accounts, cmd: port packages over to the new logging system 2017-02-23 12:16:46 +02:00
Péter Szilágyi
61e6bb1247 eth, les, swarm: fix go vet issues sufraced by log15 2017-02-23 12:16:45 +02:00
Péter Szilágyi
d4fd06c3dc all: blidly swap out glog to our log15, logs need rework 2017-02-23 12:16:44 +02:00
Péter Szilágyi
47af53f9aa log: implement a glog style pattern matching handler 2017-02-23 12:00:05 +02:00
Péter Szilágyi
3f923f3902 swarm: remove superfluous line break in log statements 2017-02-23 12:00:04 +02:00
Péter Szilágyi
189dee26c6 p2p: remove trailing newlines from log messages 2017-02-23 12:00:04 +02:00
Péter Szilágyi
b9d48b4a93 log: add support for trace level, exit on critical 2017-02-23 12:00:03 +02:00
Péter Szilágyi
ec7f81f4bc log, vendor: vendor in log15 inline into our codebase 2017-02-23 12:00:02 +02:00
gluk256
29fac7de44 Whisper API fixed (#3687)
* whisper: wnode updated for tests with geth

* whisper: updated processing of incoming messages

* whisper: symmetric encryption updated

* whisper: filter id type changed to enhance security

* whisper: allow filter without topic for asymmetric encryption

* whisper: POW updated

* whisper: logging updated

* whisper: spellchecker update

* whisper: error handling changed

* whisper: JSON field names fixed
2017-02-23 09:41:47 +01:00
Nick Johnson
555273495b trie: add difference iterator (#3637)
This PR implements a differenceIterator, which allows iterating over trie nodes
that exist in one trie but not in another. This is a prerequisite for most GC
strategies, in order to find obsolete nodes.
2017-02-22 23:49:34 +01:00
Jeffrey Wilcke
024d41d0c2 core, core/state, core/vm: remove exported account getters (#3618)
Removed exported statedb object accessors, reducing the chance for nasty
bugs to creep in. It's also ugly and unnecessary to have these methods.
2017-02-22 23:29:59 +01:00
Péter Szilágyi
46ec4357e7 Merge pull request #3698 from karalabe/govet-latest-only
travis: only run go vet and misspell on latest Go
2017-02-22 17:08:00 +02:00
Péter Szilágyi
c6e716eb31 travis: only run go vet and misspell on latest Go 2017-02-22 15:40:28 +02:00
Péter Szilágyi
388803b139 Merge pull request #3682 from karalabe/update-go1.8
travis, appveyor: update builders to Go 1.8
2017-02-22 14:55:47 +02:00
Jeffrey Wilcke
4ac481b45f core/vm, crypto: support for go-fuzz (#3672) 2017-02-21 10:24:07 +01:00
Jeffrey Wilcke
94334c233e cmd/geth: added 'geth bug' command (#3684)
* cmd/geth: added 'geth bug' command

Added bug command to geth, which will open a browser window
with an issue template and some additional system information.

* cmd/geth: update bug with better infos

* cmd/geth: added browser fallback

* cmd/geth: govet yo momma
2017-02-20 15:26:21 +02:00
Péter Szilágyi
b7f010de52 tests: cleanup tester blockchain after test run (#3692) 2017-02-20 11:54:23 +01:00
Péter Szilágyi
a0c011f1a8 travis: fallback ARM64 builds to Go 1.7.5 due to compiler bug 2017-02-20 11:28:55 +02:00
Péter Szilágyi
449a850023 travis, appveyor: update builders to Go 1.8 2017-02-20 11:22:56 +02:00
Nick Johnson
e51f65af1f Merge pull request #3681 from karalabe/usb-hidapi
accounts/usbwallet: swap karalabe/gousb to karalabe/hid
2017-02-19 17:19:40 +01:00
Jeffrey Wilcke
037c8b9ae9 VERSION, params: bumped unstable version to 1.6 (#3685) 2017-02-18 09:28:15 +01:00
Martin Holst Swende
b19e5885fe core/blockchain: Change iterator in procFutureBlocks to use lru.Peek instead of Get (#3655) 2017-02-18 09:27:21 +01:00
Felix Lange
9b0af51386 crypto: add btcec fallback for sign/recover without cgo (#3680)
* vendor: add github.com/btcsuite/btcd/btcec

* crypto: add btcec fallback for sign/recover without cgo

This commit adds a non-cgo fallback implementation of secp256k1
operations.

* crypto, core/vm: remove wrappers for sha256, ripemd160
2017-02-18 09:24:12 +01:00
Jeffrey Wilcke
bf21549faa common/math: "optimised" SafeMul and added comment on Exp (#3675) 2017-02-17 18:39:43 +01:00
Péter Szilágyi
6f74fb962e Merge pull request #3683 from karalabe/swarm-go1.8-vet-fix
swarm/api/http: fix go vet issue on Go 1.8
2017-02-17 12:08:31 +02:00
Péter Szilágyi
6ec8135256 accounts/usbwallet, vendor: use hidapi instead of libusb directly 2017-02-17 12:04:21 +02:00
Péter Szilágyi
e94dfb78f8 swarm/api/http: fix go vet issue on Go 1.8 2017-02-17 11:48:26 +02:00
Péter Szilágyi
bdef758d5c Merge pull request #3679 from fjl/vendor-govendor
vendor: update dependencies with github.com/kardianos/govendor
2017-02-16 18:23:58 +02:00
Felix Lange
2c4455b12a vendor: update dependencies with github.com/kardianos/govendor 2017-02-16 13:44:09 +01:00
Felix Lange
c8695fae35 logger: remove Core verbosity level (#3659) 2017-02-15 10:14:44 +01:00
Péter Szilágyi
a973d1d523 Merge pull request #3674 from obscuren/gaz64
params: core, core/vm, miner: 64bit gas instructions
2017-02-14 18:59:00 +02:00
gluk256
15a609d5d6 whisper: interface changed to simplify the transition to v5
* whisper: mailserver test introduced, refactoring

* whisper: validation test updated

* whisper: max number of peers fixed

* whisper: verification bug fixed

* whisper: esthetic fix

* whisper: interface changed to simplify the transition to v5

* whisper: preparation for version switch
2017-02-14 16:44:47 +02:00
Jeffrey Wilcke
c12f4df910 params: core, core/vm, miner: 64bit gas instructions
Reworked the EVM gas instructions to use 64bit integers rather than
arbitrary size big ints. All gas operations, be it additions,
multiplications or divisions, are checked and guarded against 64 bit
integer overflows.

In additon, most of the protocol paramaters in the params package have
been converted to uint64 and are now constants rather than variables.

* common/math: added overflow check ops
* core: vmenv, env renamed to evm
* eth, internal/ethapi, les: unmetered eth_call and cancel methods
* core/vm: implemented big.Int pool for evm instructions
* core/vm: unexported intPool methods & verification methods
* core/vm: added memoryGasCost overflow check and test
2017-02-13 21:44:25 +01:00
Martin Holst Swende
72dcd3c58b core, eth, internal: Added debug_getBadBlocks() method (#3654)
* core,eth,internal: Added `debug_getBadBlocks()` method

When bad blocks are discovered, these are stored within geth.
An RPC-endpoint makes them availablewithin the `debug`
namespace. This feature makes it easier to discover network forks.

```

* core, api: go format + docs

* core/blockchain: Documentation, fix minor nitpick

* core: fix failing blockchain test
2017-02-13 21:44:06 +01:00
Péter Szilágyi
4ece9c6cb0 VERSION, params: start 1.5.10 development cycle 2017-02-13 19:02:57 +02:00
Péter Szilágyi
a07539fb88 Merge pull request #3671 from karalabe/1.5.9-stable
params: 1.5.9 stable
2017-02-13 18:54:59 +02:00
Péter Szilágyi
6988e5f074 Merge pull request #3670 from karalabe/docker-usb-fix
Dockerfile: support building USB on Alpine, ignore temp files
2017-02-13 18:47:27 +02:00
Péter Szilágyi
aba016da72 params: 1.5.9 stable 2017-02-13 18:38:21 +02:00
Péter Szilágyi
09aef5c0ae Dockerfile: support building USB on Alpine, ignore temp files 2017-02-13 18:31:09 +02:00
Péter Szilágyi
9b161187ec Merge pull request #3649 from ethersphere/swarm-sigterm-fix
cmd/swarm: handle SIGTERM unix signal for clean exit
2017-02-13 18:22:15 +02:00
zelig
8883f36fe3 cmd/swarm: handle SIGTERM unix signal for clean exit 2017-02-13 22:15:14 +06:30
Péter Szilágyi
0850f68fd1 Merge pull request #3668 from obscuren/revert-gas64
Revert "params: core, core/vm, miner: 64bit gas instructions (#3514)"
2017-02-13 17:13:40 +02:00
Jeffrey Wilcke
57f4e90257 Revert "params: core, core/vm, miner: 64bit gas instructions (#3514)"
This reverts commit 8b57c49490.
2017-02-13 15:15:12 +01:00
Péter Szilágyi
f8f428cc18 Merge pull request #3592 from karalabe/hw-wallets
accounts: initial support for Ledger hardware wallets
2017-02-13 15:03:16 +02:00
Viktor Trón
e23e86921b swarm/network: fix chunk integrity checks (#3665)
* swarm/network: integrity on incoming known chunks
* swarm/network: fix integrity check for incoming chunks
* swarm/storage: imrpoved integrity checking on chunks
* dbstore panics on corrupt chunk entry an prompts user to run cleandb
* memstore adds logging for garbage collection
* dbstore refactor item delete. correct partial deletes in Get
* cmd/swarm: added cleandb subcommand
2017-02-13 13:20:50 +01:00
gluk256
65ed6a9def whisper: add tests for mailserver (#3631) 2017-02-13 13:15:20 +01:00
Péter Szilágyi
e99c788155 accounts: ledger and HD review fixes
- Handle a data race where a Ledger drops between list and open
- Prolong Ledger tx confirmation window to 30 days from 1 minute
- Simplify Ledger chainid-signature calculation and validation
- Simplify Ledger USB APDU request chunking algorithm
- Silence keystore account cache notifications for manual actions
- Only enable self derivations if wallet open succeeds
2017-02-13 14:00:12 +02:00
Péter Szilágyi
c7022c1a0c accounts/usbwallet: detect and report in Ledger is in browser mode 2017-02-13 14:00:11 +02:00
Péter Szilágyi
26cd41f0c7 accounts/usbwallet: make wallet responsive while Ledger is busy 2017-02-13 14:00:10 +02:00
Péter Szilágyi
fb19846855 accounts/usbwallet: Ledger teardown on health-check failure 2017-02-13 14:00:10 +02:00
Péter Szilágyi
205ea95802 accounts, cmd, internal, node: implement HD wallet self-derivation 2017-02-13 14:00:09 +02:00
Péter Szilágyi
c5215fdd48 accounts, cmd, internal, mobile, node: canonical account URLs 2017-02-13 14:00:08 +02:00
Péter Szilágyi
fad5eb0a87 accounts, cmd, eth, internal, miner, node: wallets and HD APIs 2017-02-13 14:00:07 +02:00
Péter Szilágyi
b3c0e9d3cc accounts/usbwallet: two phase Ledger refreshes to avoid Windows bug 2017-02-13 14:00:07 +02:00
Péter Szilágyi
470b79385b accounts/usbwallet: support Ledger app version <1.0.2 2017-02-13 14:00:06 +02:00
Péter Szilágyi
1ecf99bd0f accounts/usbwallet: skip support on iOS altogether 2017-02-13 14:00:05 +02:00
Péter Szilágyi
e0fb4d1da9 build: work around CGO linker bug on pre-1.8 Go 2017-02-13 14:00:04 +02:00
Péter Szilágyi
ac2a0e615b accounts/usbwallet: initial support for Ledger wallets 2017-02-13 14:00:04 +02:00
Péter Szilágyi
52bd4e29ff vendor: pull in support for USB devices via libusb/gousb 2017-02-13 14:00:03 +02:00
Péter Szilágyi
833e4d1319 accounts, cmd, eth, internal, mobile, node: split account backends 2017-02-13 14:00:02 +02:00
Martin Holst Swende
564b60520c core: ignore 0x prefix for code in JSON genesis blocks (#3656) 2017-02-13 03:36:50 +01:00
Zahoor Mohamed
085987ff2c cmd/swarm: manifest manipulation commands (#3645) 2017-02-13 03:33:05 +01:00
Péter Szilágyi
aaf9cfd18c Merge pull request #3662 from karalabe/travis-linux-android
travis: split Android off OSX, use native image
2017-02-12 19:25:32 +02:00
Péter Szilágyi
7ff686d6ec travis: split Android off OSX, use native image 2017-02-10 19:24:37 +02:00
Péter Szilágyi
0cc9409fda Merge pull request #3648 from bas-vk/abigen
cmd/abigen: parse contract name as abi identifier
2017-02-10 12:11:43 +02:00
Maksim
6dd27e7cff swarm/storage: release chunk storage after stop swarm (#3651)
closes #3650
2017-02-08 18:01:12 +01:00
Bas van Kervel
d0eeb3ebdc cmd/abigen: parse contract name as abi identifier 2017-02-06 18:16:56 +01:00
Péter Szilágyi
fa99986143 Merge pull request #3641 from karalabe/events-init-once
event: use sync.Once for init for faster/cleaner locking
2017-02-03 14:34:12 +02:00
Diego Siqueira
6ea8eba8ce accounts/abi, internal/jsre/deps: gofmt -w -s (#3636)
Signed-off-by: DiSiqueira <dieg0@live.com>
2017-02-03 13:32:04 +01:00
Péter Szilágyi
9b5c7153c9 event: use sync.Once for init for faster/cleaner locking 2017-02-03 14:04:57 +02:00
Péter Szilágyi
d52b0c32a0 Merge pull request #3635 from holiman/hive_fixes
core/genesis: add support for setting nonce in 'alloc'
2017-02-03 14:00:18 +02:00
Péter Szilágyi
7734ead520 Merge pull request #3605 from fjl/event-feed
event: add new Subscription type and related utilities
2017-02-03 13:56:00 +02:00
Felix Lange
1bed9b3fea event: address review issues (multiple commits)
event: address Feed review issues

event: clarify role of NewSubscription function

event: more Feed review fixes

* take sendLock after dropping f.mu
* add constant for number of special cases

event: fix subscribing/unsubscribing while Send is blocked
2017-02-03 13:37:49 +02:00
Jeffrey Wilcke
8b57c49490 params: core, core/vm, miner: 64bit gas instructions (#3514)
Reworked the EVM gas instructions to use 64bit integers rather than
arbitrary size big ints. All gas operations, be it additions,
multiplications or divisions, are checked and guarded against 64 bit
integer overflows.

In additon, most of the protocol paramaters in the params package have
been converted to uint64 and are now constants rather than variables.

* common/math: added overflow check ops
* core: vmenv, env renamed to evm
* eth, internal/ethapi, les: unmetered eth_call and cancel methods
* core/vm: implemented big.Int pool for evm instructions
* core/vm: unexported intPool methods & verification methods
* core/vm: added memoryGasCost overflow check and test
2017-02-02 15:25:42 +01:00
Brian Schroeder
296450451b state: take write lock in GetNonce (#3625)
We must take a write lock here because `GetNonce` calls
`StateDB.GetStateObject`, which mutates the DB's live set.
2017-02-01 10:55:46 +01:00
Felix Lange
4f5f90222f params, VERSION: v1.5.9-unstable 2017-02-01 02:14:54 +01:00
Felix Lange
f58fb32283 params: v1.5.8-stable 2017-02-01 02:14:04 +01:00
Felix Lange
9c45b4462c Merge pull request #3607 from zsfelfoldi/light-fix2
les: fix private net issues, enable adding peers manually again
2017-02-01 02:03:43 +01:00
gluk256
690f6ea1d7 cmd/wnode, whisper: add whisper CLI tool and mail server (#3580) 2017-01-31 11:16:20 +01:00
Péter Szilágyi
1c140f7382 Merge pull request #3615 from nolash/bzzpathfix_real5
cmd/swarm, swarm/api: bzzr improve + networkid prio
2017-01-30 16:36:30 +02:00
Péter Szilágyi
e5a93bf99a swarm/api/http: add missing copyright header 2017-01-30 15:21:46 +02:00
Péter Szilágyi
f3c368ca73 Merge pull request #3624 from kaneshin/patch-01
cmd/geth, cmd/swarm: Fix to close file handler appropriately
2017-01-30 12:24:41 +02:00
Péter Szilágyi
b8823a8b34 Merge pull request #3623 from kaneshin/patch-1
build: Fix tiny typo
2017-01-29 20:46:55 +02:00
Shintaro Kaneko
355a42f36d cmd/geth, cmd/swarm: Fix to close file handler appropriately 2017-01-30 01:10:19 +09:00
Shintaro Kaneko
658bcbcbdc build: Fix tiny typo 2017-01-30 01:09:00 +09:00
nolash
7669c5b5ec cmd/swarm, swarm/api: bzzr improve + networkid prio
fixes #3444
fixes #3494
networkid override

Added comments to explain why test against 0 appears twice

* Command line overrides saved config, saved config overrides system default

---

fixes #3476
bzzr get with path

Finally a hopefully clean commit for this PR
Added check for empty path to avoid SIGSEGV in path parser and resolver
Added requested tests for empty path and non-existing manifest.
However signature for StartHTTPServer had changed.
Now it's hacked as so:

	StartHttpServer(api.API, &Server{Addr: "127.0.0.1:8504", CorsString: ""})

* Parse url before resolve when path and ENS is supplied, example
* swarm/api/http proxy server test for retrieval of subpath through get
* Removed nil entry assignment on subtrie leaf in recursive key retrieval
* Cleaned up path-or-no-path condition in proxy server get handler
* swarm: processed with gofmt refers to lash/go-ethereum@90daa7a
* swarm: Added public access method Parse alias to parse
* swarm: processed with gofmt References nolash/go-ethereum@2ec3fd7
* Rename parse to Parse, removed alias
2017-01-27 08:18:13 +01:00
Zsolt Felfoldi
a390ca5f30 les, cmd/util: disable topic discovery with --nodiscover 2017-01-27 02:52:45 +01:00
bas-vk
c46c41eae3 core/types: add unittest for tx json serialization (#3609) 2017-01-26 21:16:24 +01:00
Vivek Anand
82aa5b1de6 core: fix a small typo in blockchain.go (#3611) 2017-01-26 16:54:49 +02:00
Zsolt Felfoldi
12379c697a les: remove delayed les server starting 2017-01-26 04:23:53 +01:00
Zsolt Felfoldi
f5348e17f8 les: add unknown peers to server pool instead of rejecting them 2017-01-26 04:23:49 +01:00
Felix Lange
a2b4abd89a rpc: send nil on subscription Err channel when Client is closed
This change makes client subscriptions compatible with the new
Subscription semantics introduced in the previous commit.
2017-01-25 18:44:21 +01:00
Felix Lange
6d5e100d0d event: add new Subscription type and related utilities
This commit introduces a new Subscription type, which is synonymous with
ethereum.Subscription. It also adds a couple of utilities that make
working with Subscriptions easier. The mot complex utility is Feed, a
synchronisation device that implements broadcast subscriptions. Feed is
slightly faster than TypeMux and will replace uses of TypeMux across the
go-ethereum codebase in the future.
2017-01-25 18:44:20 +01:00
Felix Lange
1886d03faa console, internal/web3ext: remove bzz and ens extensions (#3602)
web3.js includes bzz methods and throws an error when the extension
module is reregistered. The ENS RPC API is deprecated and not exposed by
anything.
2017-01-25 16:29:40 +01:00
Felix Lange
9b62facdd4 event: deprecate TypeMux and related types
The Subscription type is gone, all uses are replaced by
*TypeMuxSubscription. This change is prep-work for the
introduction of the new Subscription type in a later commit.

   gorename -from '"github.com/ethereum/go-ethereum/event"::Event' -to TypeMuxEvent
   gorename -from '"github.com/ethereum/go-ethereum/event"::muxsub' -to TypeMuxSubscription
   gofmt -w -r 'Subscription -> *TypeMuxSubscription' ./event/*.go
   find . -name '*.go' -and -not -regex '\./vendor/.*' \| xargs gofmt -w -r 'event.Subscription -> *event.TypeMuxSubscription'
2017-01-25 16:25:57 +01:00
Martin Holst Swende
da92f5b2d6 core/genesis: add support for setting nonce in 'alloc'
This is to be able to set `pre`-state when performing blockchain tests through Hive, we need to be able to set the nonce.
2017-01-24 20:42:47 +01:00
Felix Lange
f1069a30b9 eth/downloader: improve deliverNodeData (#3588)
Commit d3b751e accidentally deleted a crucial 'return' statement,
leading to a crash in case of an issue with node data. This change
improves the fix in PR #3591 by removing the lock entirely.
2017-01-24 13:20:37 +01:00
Péter Szilágyi
2718b42828 Merge pull request #3599 from karalabe/docker-alpine-cacerts
containers/docker: update base images, add CA certs, build internally on Ubuntu
2017-01-24 13:46:56 +02:00
Felix Lange
fc52f2c007 core/types: make Transaction zero value printable (#3595) 2017-01-23 18:51:02 +01:00
Péter Szilágyi
0b9070fe01 containers/docker: update ubuntu images to build, not pull 2017-01-23 12:12:38 +02:00
Péter Szilágyi
c04598f2b0 containers/docker: update to alpine 3.5, add CA certificates 2017-01-23 11:46:15 +02:00
Felix Lange
96778a1c21 crypto/secp256k1: sign with deterministic K (rfc6979) (#3561) 2017-01-22 23:28:47 +01:00
Martin Holst Swende
935d891e9d cmd/evm: added debug flag (back) (#3554)
* evm: added debug flag (back)

* cmd/evm: gofmt
2017-01-22 22:14:09 +01:00
Péter Szilágyi
682875adff accounts/abi/bind, internal/ethapi: binary search gas estimation (#3587)
Gas estimation currently mostly works, but can underestimate for more funky
refunds. This is because various ops (e.g. CALL) need more gas to run than they
actually consume (e.g. 2300 stipend that is refunded if not used). With more
intricate contract interplays, it becomes almost impossible to return a proper
value to the user.

This commit swaps out the simplistic gas estimation to a binary search approach,
honing in on the correct gas use. This does mean that gas estimation needs to
rerun the transaction log(max-price) times to measure whether it fails or not,
but it's a price paid by the transaction issuer, and it should be worth it to
support proper estimates.
2017-01-20 23:39:16 +01:00
bas-vk
0126d01435 types: bugfix invalid V derivation on tx json unmarshal (#3594) 2017-01-20 23:32:16 +01:00
Péter Szilágyi
946db8ba65 internal/guide: initial test suite to ensure guide snippets run ok (#3582) 2017-01-20 11:50:21 +01:00
Péter Szilágyi
7814a8e131 travis: Install Android NDK explicitly, removed from gomobile (#3593)
The Android NDK was recently removed from gomobile, leading to our Android
builds failing. Starting from https://go-review.googlesource.com/#/c/35173/ ,
gomobile requires a locally installed NDK. This PR ensures that travis installs
that too before running the build steps.
2017-01-20 10:33:58 +01:00
Péter Szilágyi
ebc3d232f4 eth/downloader: fix mutex regression causing panics on fail (#3591) 2017-01-20 01:12:14 +01:00
Péter Szilágyi
f087c66f95 Merge pull request #3584 from obscuren/dead-code
core: removal of dead-code
2017-01-18 13:36:21 +02:00
Jeffrey Wilcke
508fdc3496 core: removal of dead-code
Removal of dead code that appeard as if we had a consensus issue. This
however is not the case as the proper error catching happens in the vm
package instead.
2017-01-17 21:50:08 +01:00
Péter Szilágyi
d63752ef4d Merge pull request #3579 from bas-vk/natspec
cmd,eth,les,internal: remove natspec support
2017-01-17 14:38:57 +02:00
Martin Holst Swende
6fb76443b3 core/blockchain: Made logging of reorgs more structured (#3573)
* core: Made logging of reorgs more structured, also always log if reorg is > 63 blocks long

* core/blockchain: go fmt

* core/blockchain: Minor fixes to the reorg reporting
2017-01-17 14:10:26 +02:00
Péter Szilágyi
2eefed84c9 Merge pull request #3581 from karalabe/accounts-polish
accounts, mobile: make account manager API a bit more uniform
2017-01-17 14:09:29 +02:00
Péter Szilágyi
230530f5ea accounts, mobile: make account manager API a bit more uniform 2017-01-17 13:25:36 +02:00
Nick Johnson
17d92233d9 cmd/geth, core: add support for recording SHA3 preimages (#3543) 2017-01-17 12:19:50 +01:00
Bas van Kervel
54a65e6d87 cmd,eth,les,internal: remove natspec support 2017-01-17 12:13:50 +01:00
Felix Lange
26d385c18b params, VERSION: 1.5.8 unstable 2017-01-16 11:12:50 +01:00
Felix Lange
da2a22c384 params: stable 1.5.7 2017-01-16 10:57:02 +01:00
Felföldi Zsolt
0fa9a8929c les: fixed transaction sending deadlock (#3568) 2017-01-16 10:51:29 +01:00
Péter Szilágyi
2a1a531ba3 Merge pull request #3570 from fjl/hexutil-zero-fix
common/hexutil: fix EncodeBig, Big.MarshalJSON
2017-01-16 11:49:17 +02:00
Felix Lange
51f6b6d33f common/hexutil: fix EncodeBig, Big.MarshalJSON
The code was too clever and failed to include zeros on a big.Word
boundary.
2017-01-16 10:32:40 +01:00
Péter Szilágyi
b5a100b859 Merge pull request #3560 from karalabe/ci-misspell
travis, appveyor, build: add source spell checking
2017-01-13 12:16:22 +02:00
Péter Szilágyi
54fcab20e3 appveyor, build: fix review requests 2017-01-13 12:04:55 +02:00
Péter Szilágyi
a2bc90d1d7 build: spellcheck individual packages (Windows path limits) 2017-01-13 11:22:24 +02:00
Péter Szilágyi
c01f8c3d3c accounts/abi: fix comment spelling error 2017-01-13 11:14:47 +02:00
Péter Szilágyi
e4181a7f1b travis, appveyor, build: add source spell checking 2017-01-13 11:14:13 +02:00
Felix Lange
01f6f2d741 common/hexutil: allow empty strings when decoding JSON (#3559) 2017-01-13 09:45:40 +01:00
Felix Lange
c5df37c111 eth: accept leading zeros for nonce parameter of submitWork (#3558) 2017-01-13 00:37:23 +01:00
Felix Lange
e0ceeab0d1 crypto/secp256k1: update to github.com/bitcoin-core/secp256k1 @ 9d560f9 (#3544)
- Use defined constants instead of hard-coding their integer value.
- Allocate secp256k1 structs on the C stack instead of converting []byte
- Remove dead code
2017-01-12 21:29:11 +01:00
Péter Szilágyi
93077c98e4 internal: update web3.js to 0.18.1, embed deps with go-bindata (#3545) 2017-01-12 21:28:35 +01:00
Péter Szilágyi
3dab303826 Merge pull request #3555 from obscuren/unskip-test
tests: unskip test
2017-01-12 12:08:56 +02:00
Jeffrey Wilcke
3160fd24ba tests: unskip test 2017-01-12 10:32:21 +01:00
Péter Szilágyi
ce7822c130 Merge pull request #3553 from bas-vk/rm-olympic-support
core: remove support for Olympic network
2017-01-12 11:26:00 +02:00
Bas van Kervel
745a3adebd core: remove support for Olympic network 2017-01-12 09:50:54 +01:00
Péter Szilágyi
218ec6c085 Merge pull request #3551 from fjl/core-import-log-align
core: improve import log alignment
2017-01-11 14:53:54 +02:00
Nick Johnson
d30d7800e0 ethdb: Implement interface for prefixed operations to the DB (#3536) 2017-01-11 13:26:09 +01:00
Felix Lange
8820d97039 internal/ethapi: fix duration parameter of personal_unlockAccount (#3542) 2017-01-11 13:20:24 +01:00
Péter Szilágyi
b52fde7cf7 Merge pull request #3546 from fjl/deps-update
vendor: update dependencies
2017-01-11 12:14:08 +02:00
Péter Szilágyi
2b4d0b6ff9 Merge pull request #3548 from fjl/geth-fix-bootnodes
cmd/utils: fix comma-separated --bootnodes
2017-01-11 10:59:14 +02:00
Felix Lange
21f1370d2a core: improve import log alignment 2017-01-10 23:14:08 +01:00
Felix Lange
d78f9b834a vendor: update all dependencies except Azure SDK
The Azure SDK doesn't support Go 1.5 anymore. We can't upgrade it until
Go 1.8 comes out.
2017-01-10 22:33:24 +01:00
Felix Lange
445deb7470 cmd/utils: fix comma-separated --bootnodes 2017-01-10 21:13:43 +01:00
Péter Szilágyi
02b67558e8 Merge pull request #3535 from fjl/all-ineffassign
all: fix ineffectual assignments
2017-01-09 23:53:17 +02:00
Péter Szilágyi
91c8f87fb1 Merge pull request #3538 from karalabe/cycle-1.5.7
params, VERSION: start 1.5.7 release cycle
2017-01-09 17:47:35 +02:00
Péter Szilágyi
d056b7fa52 params, VERSION: start 1.5.7 release cycle 2017-01-09 17:45:49 +02:00
Péter Szilágyi
2a609af518 Merge pull request #3537 from karalabe/release-1.5.6
params: stable version 1.5.6
2017-01-09 17:39:27 +02:00
Péter Szilágyi
1d5d6616ae params: stable version 1.5.6 2017-01-09 17:30:35 +02:00
Felix Lange
b9b3efb09f all: fix ineffectual assignments and remove uses of crypto.Sha3
go get github.com/gordonklaus/ineffassign
ineffassign .
2017-01-09 16:24:42 +01:00
Felix Lange
0f34d506b5 generators: delete dead code
We don't use this anymore.
2017-01-09 16:12:54 +01:00
Felix Lange
5eccc122e8 build, node: fix go vet nits 2017-01-09 16:12:54 +01:00
Péter Szilágyi
681b51aac4 Merge pull request #3519 from zsfelfoldi/light-topic5
les: fixed selectPeer deadlock, improved request distribution
2017-01-09 16:58:23 +02:00
Péter Szilágyi
4268cb8efe Merge pull request #3534 from bas-vk/writemipmaprace
core: fix race condition in WriteMipmapBloom
2017-01-09 16:58:05 +02:00
Viktor Trón
3f1a72908c cmd/swarm: uploader uses HTTP PUT for directories (#3488) 2017-01-09 15:19:56 +01:00
Bas van Kervel
2fed476ce1 core: fix race condition in WriteMipmapBloom 2017-01-09 15:35:58 +02:00
Péter Szilágyi
6cb39dd3da Merge pull request #3529 from fjl/console-error-fix
console: fix error message in faux JSON-RPC responses
2017-01-09 13:46:15 +02:00
Péter Szilágyi
88cc1ca55a Merge pull request #3533 from karalabe/modum-io-develop-2
accounts/abi: support custom int slice types
2017-01-09 11:49:17 +02:00
Thomas Bocek
1bd9769111 accounts/abi: fixed broken types slice testcases
Check for slice in type as well and adapted test case as arrays
also store its types.
2017-01-09 11:36:33 +02:00
Jeffrey Wilcke
47372813ef accounts/abi: fixed comments 2017-01-09 11:36:33 +02:00
tbocek
fc213c873d accounts/abi: added testcase to unpack []uint32 2017-01-09 11:36:32 +02:00
Thomas Bocek
972f0bd3db accounts/abi: support custom int slice types
On solidity contract I have "uint32 []" type, when abigen creates Go
bindings - they are also "[]uint32" type on Go side. Even though it
looks like it should work - the actual type of the data coming from
the chain is of type " []*big.Int".

When executing contract function from Go side - getting unmarshal error:
abi: cannot unmarshal []*big.Int in to []uint32

The fix is to create array with the correct type

This fixed the issue reported in: https://github.com/ethereum/go-ethereum/issues/2802
2017-01-09 11:36:31 +02:00
Victor Farazdagi
808310a569 node: fix pointer dereference issue in StartRPC (#3532) 2017-01-08 15:55:37 +01:00
Valentin Wüstholz
0a5450fe04 cmd/disasm: fix array-out-of-bounds error (#3491) 2017-01-08 01:18:22 +01:00
Felix Lange
9bab0b8a24 console: fix error message in faux JSON-RPC responses
The message was used as both key and value in the error object.
This only affected unusual errors with no error code.
2017-01-08 00:55:48 +01:00
Péter Szilágyi
17182732f5 Merge pull request #3526 from karalabe/misspell
all: fix spelling errors
2017-01-06 20:03:44 +02:00
Péter Szilágyi
18c77744ff all: fix spelling errors 2017-01-06 19:44:35 +02:00
Péter Szilágyi
ac93a6ff6c Merge pull request #3525 from fjl/all-gosimple-cleanup
all: clean up lint issues, remove more dead code
2017-01-06 19:30:44 +02:00
Felix Lange
13e3b2f433 logger, pow/dagger, pow/ezp: delete dead code 2017-01-06 18:18:07 +01:00
Felix Lange
f2da6581ba all: fix issues reported by honnef.co/go/simple/cmd/gosimple 2017-01-06 18:18:07 +01:00
Péter Szilágyi
444fc892b0 Merge pull request #3524 from karalabe/mobile-signwith-swift-fixup
mobile: rename passphrase signing method to avoid Swift rewrite
2017-01-06 18:04:19 +02:00
Péter Szilágyi
b56aee3697 mobile: rename passphrase signing method to avoid Swift rewrite 2017-01-06 17:47:15 +02:00
Felix Lange
35a7dcb162 all: gofmt -w -s 2017-01-06 15:52:03 +01:00
Felix Lange
e0fde02290 common/compiler: remove workaround for solc 0.3.5 stdin bug (#3522)
The crash when compiling stdin was fixed in solc 0.3.6 (released
2016-08-10). While here, simplify the test so it runs with any solc
version.

Fixes #3484. The byte code was different for each run because recent
solc embeds the swarm hash of contract metadata into the code. When
compiling from stdin the name in the metadata is constant.
2017-01-06 15:39:35 +01:00
Péter Szilágyi
59b8245bbc Merge pull request #3516 from fjl/types-drop-sign-ecdsa
core/types: remove redundant SignECDSA wrappers, rename to SignTx
2017-01-06 15:55:55 +02:00
Péter Szilágyi
8f9daaa3ba Merge pull request #3518 from fjl/ethclient-dependency-cleanup
core/types: dependency cleanup
2017-01-06 15:42:03 +02:00
Felix Lange
d3b751e4d9 trie: remove dependency on ethdb
This removes the core/types -> leveldb dependency.
2017-01-06 14:15:22 +01:00
Felix Lange
7731061903 core/vm: move Log to core/types
This significantly reduces the dependency closure of ethclient, which no
longer depends on core/vm as of this change.

All uses of vm.Logs are replaced by []*types.Log. NewLog is gone too,
the constructor simply returned a literal.
2017-01-06 14:15:22 +01:00
Felix Lange
b9683d3748 params: avoid importing p2p/discover for bootnodes
params is imported by leaf-ish library packages and should not pull in
the p2p stack.
2017-01-06 14:15:21 +01:00
Zsolt Felfoldi
66979aa468 light: fixed data race in TestTxPool 2017-01-06 04:34:35 +01:00
Zsolt Felfoldi
93f9c023cc les: fixed selectPeer deadlock, improved request distribution
les/flowcontrol: using proper types for relative and absolute times
2017-01-06 04:34:31 +01:00
Péter Szilágyi
e0ee0cc66a Merge pull request #3517 from karalabe/empty-ios-prefix
build: finally settle on empty iOS ObjC package prefixes
2017-01-05 15:29:36 +02:00
Péter Szilágyi
9b135a9c20 build: finally settle on empty iOS ObjC package prefixes 2017-01-05 14:32:30 +02:00
Felix Lange
e171bf74f8 core/types: remove redundant SignECDSA wrappers, rename to SignTx 2017-01-05 12:59:17 +01:00
Péter Szilágyi
bb2e99dfc2 Merge pull request #3417 from karalabe/mobile-polishes
Account management API polishes
2017-01-05 13:57:12 +02:00
Péter Szilágyi
b37d175e59 accounts, internal, mobile: polish accounts API, extend Android tests 2017-01-05 12:58:03 +02:00
Maran
f087633efd swarm/api/http: add support for CORS headers (#3388) 2017-01-05 11:57:41 +01:00
Péter Szilágyi
bbce726c8a Merge pull request #3515 from bas-vk/exportropsten
core,cmd/utils: bugfix for ropsten dump imports
2017-01-05 12:54:45 +02:00
Jeffrey Wilcke
bbc4ea4ae8 core/vm: improved EVM run loop & instruction calling (#3378)
The run loop, which previously contained custom opcode executes have been
removed and has been simplified to a few checks.

Each operation consists of 4 elements: execution function, gas cost function,
stack validation function and memory size function. The execution function
implements the operation's runtime behaviour, the gas cost function implements
the operation gas costs function and greatly depends on the memory and stack,
the stack validation function validates the stack and makes sure that enough
items can be popped off and pushed on and the memory size function calculates
the memory required for the operation and returns it.

This commit also allows the EVM to go unmetered. This is helpful for offline
operations such as contract calls.
2017-01-05 11:52:10 +01:00
RJ
2126d81488 accounts/abi: add support for function types (#3405) 2017-01-05 11:46:44 +01:00
Péter Szilágyi
06b381d1c9 cmd/utils: disallow --fakepow for live operation (#3512) 2017-01-05 11:40:56 +01:00
Péter Szilágyi
08eea0f0e4 accounts, core, crypto, internal: use normalised V during signature handling (#3455)
To address increasing complexity in code that handles signatures, this PR
discards all notion of "different" signature types at the library level. Both
the crypto and accounts package is reduced to only be able to produce plain
canonical secp256k1 signatures. This makes the crpyto APIs much cleaner,
simpler and harder to abuse.
2017-01-05 11:35:23 +01:00
Bas van Kervel
a1798a8188 core,cmd/utils: bugfix for ropsten dump imports 2017-01-05 11:31:57 +01:00
Péter Szilágyi
0fac8cba47 Merge pull request #3511 from karalabe/live-fakepow
cmd/utils, eth, les: bubble --fakepow flag into eth/les too
2017-01-04 13:27:51 +02:00
Péter Szilágyi
1ca74aba6f Merge pull request #3505 from bas-vk/txinblock
ethclient: hex encode request args for TransactionInBlock
2017-01-04 12:43:27 +02:00
Péter Szilágyi
2ce30382d9 cmd/utils, eth, les: bubble --fakepow flag into eth/les too 2017-01-04 10:42:41 +02:00
Bas van Kervel
8bc545be2a ethclient: hex encode request args for TransactionInBlock 2017-01-03 14:46:00 +01:00
Péter Szilágyi
891fcd8ce1 Merge pull request #3486 from bas-vk/txbyhash
ethclient: pass ptr when parsing eth_getTransactionByHash result
2017-01-03 10:56:22 +02:00
Guillaume NICOLAS
bd06091874 mobile: add SetVerbosity (#3492) 2017-01-02 18:12:31 +01:00
Péter Szilágyi
3e3edcc465 Merge pull request #3490 from karalabe/fix-miner-api
eth: fix miner start API to accept int, not hexint
2016-12-23 14:59:26 +02:00
Péter Szilágyi
89a32267f7 eth: fix miner start API to accept int, not hexint 2016-12-23 11:28:11 +02:00
Bas van Kervel
021177ca9b ethclient: pass ptr when parsing eth_getTransactionByHash result 2016-12-22 14:45:01 +01:00
Péter Szilágyi
115364b0a9 Merge pull request #3475 from fjl/rpc-hex-improvements
rpc: remove HexBytes, HexNumber
2016-12-22 13:49:16 +02:00
bas-vk
6d15d00ac4 accounts/abi: add support for "anonymous" and "indexed" for events (#3464) 2016-12-22 01:51:20 +01:00
Valentin Wüstholz
bdaa43510b cmd/disasm: fix off-by-one error and improve error handling (#3482) 2016-12-22 00:37:27 +01:00
Aron Fischer
9a51f5c350 swarm/http: check error returned by reader.Size (#3470) 2016-12-22 00:35:05 +01:00
Aron Fischer
301c0a6303 swarm/storage: call size before seek-from-end (#3469) 2016-12-22 00:34:05 +01:00
Aron Fischer
65f486ff02 swarm/api: check for zero length manifest error (#3468) 2016-12-22 00:32:08 +01:00
Péter Szilágyi
df096a7771 Merge pull request #3479 from karalabe/android-ropsten-dao
mobile: fix ropsten chain configs
2016-12-21 13:25:00 +02:00
Péter Szilágyi
0e9a9f243f mobile: fix ropsten chain configs 2016-12-21 13:10:57 +02:00
Felix Lange
12c964b2b7 internal/ethapi: fix hex handling for eth_call input and eth_sendRawTransaction 2016-12-20 14:46:22 +01:00
Felix Lange
cf71f5cd60 rpc: remove HexNumber, replace all uses with hexutil types
This change couldn't be automated because HexNumber was used for numbers
of all sizes.
2016-12-20 14:41:58 +01:00
Felix Lange
adab2e16bd rpc: remove HexBytes, replace all uses with hexutil.Bytes 2016-12-20 14:35:26 +01:00
Felix Lange
a3e3235d97 rpc: improve error messages for invalid arguments
The message now includes the index of the invalid arg.
2016-12-20 14:35:26 +01:00
Felix Lange
2be3c4b0e3 internal/jsre: fix built-in inspect function
inspect was broken by ffaf58f0a9 (May 2016!).
Looks like nobody uses this function.
2016-12-20 14:35:14 +01:00
Péter Szilágyi
0ee796632a eth, miner: verify PoW in the remote agent to notify submitter (#3438) 2016-12-20 02:14:36 +01:00
Nick Johnson
1fe67c125d eth/filters: add FindOnce for iterator-like operation (#3435)
This commit introduces a FindOnce method for filters. FindOnce finds the next block that
matches the filter and returns all matching logs from that block. If there are no further
matching logs, it returns a nil slice. This method allows callers to iterate over large
sets of logs progressively.

The changes introduce a small inefficiency relating to mipmaps: the first time a filter is
called, it acts as if all mipmaps are matched, and thus iterates several blocks near the
requested start point. This is in the interest of simplicity and avoiding duplicate mipmap
lookups each time FindOnce is called.
2016-12-20 02:00:03 +01:00
gluk256
ba996f5e27 whisper: refactoring (#3411)
* whisper: refactored message processing
* whisper: final polishing
* whisper: logging updated
* whisper: moved the check, changed the default PoW
* whisper: refactoring of message queuing
* whisper: refactored parameters
2016-12-20 00:58:01 +01:00
Péter Szilágyi
64bf5bafe9 Merge pull request #3403 from VoR0220/fixedPointsAbi
accounts/abi: prepare ABI to handle fixed point types
2016-12-19 14:22:57 +02:00
Péter Szilágyi
4d05bbf2a4 accounts/abi: clean up PR and add type parsing tests 2016-12-19 14:11:11 +02:00
VoR0220
471990f771 accounts/abi: prepare ABI to handle fixed point types
Signed-off-by: VoR0220 <rj@erisindustries.com>
2016-12-19 14:11:11 +02:00
Péter Szilágyi
7b623aab9d Merge pull request #3454 from karalabe/allow-zeroprice-tx
core: allow zero priced transactions from inexistent accounts too
2016-12-19 12:23:46 +02:00
Péter Szilágyi
e871ae1270 Merge pull request #3453 from fjl/api-sign-recover-hex
internal/ethapi: fix hex handling for eth_sign, personal_{sign,recover}
2016-12-19 11:49:21 +02:00
Péter Szilágyi
c44830ebf3 core, light: allow zero cost txs from inexistent accounts too 2016-12-16 13:30:39 +02:00
Felix Lange
3e4a04f34d internal/ethapi: fix hex handling for eth_sign, personal_{sign,recover} 2016-12-16 11:32:51 +01:00
Péter Szilágyi
38827dd9ca Merge pull request #3445 from karalabe/govet-ip-signal
p2p/nat: fix a bytes based net.IP comparison
2016-12-15 16:51:14 +02:00
Péter Szilágyi
21fd9f037e p2p/nat: fix a bytes based net.IP comparison 2016-12-15 16:28:31 +02:00
Péter Szilágyi
033763eaf7 Merge pull request #3442 from karalabe/discv5-fix-ip-comparison
p2p/discover, p2p/discv5: use flexible comparison for IPs
2016-12-14 19:15:05 +02:00
Péter Szilágyi
2573094df2 p2p/discover, p2p/discv5: use flexible comparison for IPs 2016-12-14 18:40:49 +02:00
Péter Szilágyi
745026b7b4 Merge pull request #3433 from karalabe/badblock-order-fix
core: import future blocks one-by-one, enfore chain ancestry
2016-12-14 16:45:48 +02:00
Péter Szilágyi
a07d955eaa Merge pull request #3441 from karalabe/begin-1.5.6-cycle
VERSION, params: start Geth 1.5.6 development cycle
2016-12-14 16:28:45 +02:00
Péter Szilágyi
9d6f4e2e7f VERSION, params: start Geth 1.5.6 development cycle 2016-12-14 16:27:35 +02:00
Péter Szilágyi
ff07d54843 Merge pull request #3440 from karalabe/release-1.5.5
params: stable version 1.5.5
2016-12-14 16:06:54 +02:00
Péter Szilágyi
e53879328c params: stable version 1.5.5 2016-12-14 15:57:44 +02:00
Péter Szilágyi
b792412d31 Merge pull request #3430 from karalabe/miner-pending-race
miner: clean up unconfirmed mined block tracking
2016-12-14 15:05:50 +02:00
Péter Szilágyi
49c6f1053c Merge pull request #3421 from ethersphere/s/swarm-cmd
cmd/swarm: one command  with subcommands
2016-12-14 12:26:20 +02:00
Péter Szilágyi
4d960f6dc6 Merge pull request #3439 from karalabe/drop-deprecated-wily
build: Ubuntu wily was officially deprecated, drop support
2016-12-14 12:18:03 +02:00
Péter Szilágyi
8941665896 build: Ubuntu wily was officially deprecated, drop support 2016-12-14 11:45:14 +02:00
Péter Szilágyi
9cc0f60666 Merge pull request #3429 from bas-vk/txpool-crash
core: init pending state in tx pool on creation
2016-12-14 11:17:39 +02:00
Péter Szilágyi
fdb8edf5ea Merge pull request #3427 from Arachnid/gzipdump
cmd/utils, eth: Add gzip support for chain dump and restore
2016-12-14 11:15:21 +02:00
Nick Johnson
9ba9fe818d cmd/utils, eth: Add gzip support for chain dump and restore 2016-12-14 08:59:55 +00:00
zelig
92224d27b1 cmd/swarm: testnet bootnodes IP address change 2016-12-14 08:14:52 +01:00
Péter Szilágyi
157a4bd926 Merge pull request #3437 from karalabe/update-ci-go1.7.4
travis, appveyor: build with Go 1.7.4
2016-12-13 22:30:14 +02:00
Péter Szilágyi
29d6881112 travis, appveyor: build with Go 1.7.4 2016-12-13 19:54:56 +02:00
Péter Szilágyi
e2692921e1 Merge pull request #3434 from karalabe/drop-legacy-android
cmd/geth: drop legacy android code
2016-12-13 18:53:06 +02:00
Péter Szilágyi
b63138c3ec cmd/geth: drop legacy android code 2016-12-13 18:17:49 +02:00
Péter Szilágyi
a59fcc33e6 core: import future blocks one-by-one, enfore chain ancestry 2016-12-13 16:19:45 +02:00
Péter Szilágyi
07311f3157 miner: rename pending to unconformed, add bounds and ops tests 2016-12-13 15:10:52 +02:00
Péter Szilágyi
17637ed1bb miner: clean up unconfirmed mined block tracking 2016-12-13 14:31:32 +02:00
Péter Szilágyi
f15828e901 Merge pull request #3431 from karalabe/miner-race-fixes
Miner race fixes
2016-12-13 14:30:26 +02:00
Péter Szilágyi
dadd689359 miner: fix data race on setting etherbase/extradata 2016-12-13 14:04:05 +02:00
Péter Szilágyi
b750cab56a miner: fix a race between remote agent start/loop 2016-12-13 14:03:57 +02:00
zelig
485748c416 cmd/swarm: improve uploader output and add defaultpath option 2016-12-13 12:54:13 +01:00
zelig
080699f7df cmd/swarm: ethapi not required 2016-12-13 12:54:13 +01:00
zelig
8e35f54931 cmd/swarm: trim trailing slash from bzzapi url 2016-12-13 12:54:13 +01:00
zelig
d44f1a77ee cmd/swarm: add default bootnodes for testnet 3 2016-12-13 12:54:13 +01:00
zelig
4181046488 swarm/network, cmd/swarm: swarm default network id is 3 (to match Ropsten) 2016-12-13 12:54:13 +01:00
zelig
d7c398b638 build: add swarm command to binary packages, update README 2016-12-13 12:54:13 +01:00
zelig
5f5d0aa4ff cmd/swarm: subsume cmd/bzz* as subcommands under swarm
cmd/swarm: subsume cmd/bzz* under cmd/swarm as subcommands
2016-12-13 12:54:05 +01:00
Bas van Kervel
9f1520b4c0 core: init pending state in tx pool on creation 2016-12-13 10:38:04 +01:00
Felix Lange
a98e8c0889 Merge pull request #3413 from zsfelfoldi/light-topic4
les, p2p/discv5: implement server pool, improve peer selection, light fetcher and topic searching
2016-12-12 20:46:15 +01:00
Péter Szilágyi
ee445a2ba4 Merge pull request #3425 from karalabe/netstats-time-fixup
netstats: time and block history
2016-12-12 14:55:00 +02:00
Péter Szilágyi
b2c226cb7d ethstats: implement block history retrievals 2016-12-12 14:01:52 +02:00
Péter Szilágyi
13614f4e1c ethstats: fix timestamps and add custom proto support 2016-12-11 20:16:30 +02:00
bas-vk
4f9ccdd70f build: safe update of PATH on Windows (#3419)
NSIS has a default MAX_STR_LEN of 1024. If $ENV{PATH} is longer
the returned string is truncated to an empty string. Its then not
possible to distinguis between the variable not set or too long.
As a result the variable is set with the location where geth and/or
dev tools are installed. This may override any previous set values.
2016-12-11 00:01:57 +01:00
bas-vk
4e36b1e3da core: bugfix state change race condition in txpool (#3412)
The transaction pool keeps track of the current nonce in its local pendingState. When a
new block comes in the pendingState is reset. During the reset it fetches multiple times
the current state through the use of the currentState callback. When a second block comes
in during the reset its possible that the state changes during the reset. If that block
holds transactions that are currently in the pool the local pendingState that is used to
determine nonces can get out of sync.
2016-12-10 23:54:58 +01:00
Zsolt Felfoldi
f12f8a6c14 les, light: add block availability check for ODR requests 2016-12-10 09:53:25 +01:00
Zsolt Felfoldi
c57c54ce96 eth, les: defer starting LES service until ETH initial sync is finished 2016-12-10 09:53:25 +01:00
Zsolt Felfoldi
c8130df1d9 les: using random request IDs 2016-12-10 09:53:25 +01:00
Zsolt Felfoldi
af8a742d00 les: improved header fetcher and server statistics 2016-12-10 09:53:08 +01:00
Zsolt Felfoldi
e67500aa15 les: fixed light fetcher request ID matching 2016-12-08 13:38:15 +01:00
Zsolt Felfoldi
a6d3bf6fc3 p2p/discv5: search and lookup improvement 2016-12-08 13:38:15 +01:00
Zsolt Felfoldi
3e617f3cd6 les: implement light server pool 2016-12-08 13:38:15 +01:00
Péter Szilágyi
0fe35b907a mobile: iOS naming and API fixes for generators and Swift (#3408)
* build: modify the iOS namespace to iGeth (gomobile limitation)
* mobile: assign names to return types for ObjC wrapper
* mobile: use more expanded names for iOS/Swift API
2016-12-08 13:09:26 +01:00
Jeffrey Wilcke
3fc7c97827 core, core/vm: implemented a generic environment (#3348)
Environment is now a struct (not an interface). This
reduces a lot of tech-debt throughout the codebase where a virtual
machine environment had to be implemented in order to test or run it.

The new environment is suitable to be used en the json tests, core
consensus and light client.
2016-12-06 02:16:03 +01:00
Felix Lange
7f79d249a6 Merge pull request #3402 from fjl/ethclient-api-fixes
eth/filters, ethclient, ethereum: API improvements
2016-12-05 20:08:18 +01:00
Felix Lange
f138374027 ethereum: document use of Removed field for SubscribeFilterLogs 2016-12-05 10:57:11 +01:00
Felix Lange
f52a1ae849 core, core/vm, eth/filters: move Removed field into vm.Log
This field used to be assigned by the filter system and returned through
the RPC API. Now that we have a Go client that uses the underlying type,
the field needs to move. It is now assigned to true when the RemovedLogs
event is generated so the filter system doesn't need to care about the
field at all.

While here, remove the log list from ChainSideEvent. There are no users
of this field right now and any potential users could subscribe to
RemovedLogsEvent instead.
2016-12-05 10:57:11 +01:00
Felix Lange
3bc0fe1ee3 ethclient, ethereum: add NotFound, split transactions out of ChainReader
ethclient now returns ethereum.NotFound if the server returns null and
no error while accessing blockchain data.

The light client cannot provide arbitrary transactions. The change to
split transaction access into its own interface emphasizes that
transactions should not be relied on and recommends use of logs.
2016-12-05 10:57:11 +01:00
Felix Lange
fa0cc27400 ethclient: use package hexutil for number encoding 2016-12-04 19:45:55 +01:00
Felix Lange
4cb29bde2e ethclient: don't crash if server returns null uncle header
It should never return null for a known uncle, but even if it does
we can't just crash.
2016-12-04 19:45:55 +01:00
gluk256
2dcf75a722 whisper/shhapi, whisper/whisperv5: refactoring (#3364)
* Filter refactoring
* API tests added + bugfix
* fixed the error logs
* FilterID fixed
* test cases fixed
* key generation updated
* POW updated
* got rid of redundant stuff
2016-12-01 20:09:22 +01:00
Nick Johnson
671fd94e25 swarm/api: Update ENS root address for Ropsten & prod (#3391) 2016-12-01 19:33:10 +01:00
Péter Szilágyi
717d2f6f9e Merge pull request #3390 from bas-vk/statsd-stop
ethstats: check if received event is valid
2016-12-01 10:30:19 +02:00
Maran
8cb95cb916 README: removed develop mentions 2016-11-30 19:39:05 +01:00
Bas van Kervel
56b446190a ethstats: check if received event is valid 2016-11-30 17:47:39 +01:00
Péter Szilágyi
86f9e836be cmd/geth: tidied up the source (#3385)
cmd/geth: tidied up the source
2016-11-30 13:34:24 +02:00
Péter Szilágyi
a90a170361 Merge pull request #3373 from karalabe/ethstats-block-fields
ethstats: don't drop concurrent head reports (mini forks)
2016-11-30 12:36:22 +02:00
Péter Szilágyi
889a5e0cf1 Merge pull request #3368 from bas-vk/sha3
node: improve error handling for web3_sha3 RPC method
2016-11-30 12:10:05 +02:00
Martin Holst Swende
9f8bc00cf5 eth, miner: removed unnecessary state.Copy()
* miner: removed unnecessary state.Copy()

* eth: made use of new miner method without state copying

* miner: More documentation about new method
2016-11-30 11:48:48 +02:00
Luca Zeug
3363a1c227 cmd/utils: update helpscreen's testnet description (#3377) 2016-11-29 16:23:11 +02:00
Péter Szilágyi
fc9939c4e1 Merge pull request #3376 from karalabe/drop-dao-flags
cmd: drop DAO related choice flags since ETC diverged
2016-11-29 16:12:40 +02:00
Péter Szilágyi
7267f796e6 cmd: drop DAO related choice flags since ETC diverged 2016-11-29 15:50:27 +02:00
Péter Szilágyi
7dfeceb8cc ethstats: don't drop concurrent head reports (mini forks) 2016-11-29 14:17:20 +02:00
Péter Szilágyi
3807e520ec Merge pull request #3370 from karalabe/ethstats-block-fields
ethstats: report block miner, gas limit and gas consumption
2016-11-29 13:15:58 +02:00
Péter Szilágyi
7625b1a4f4 ethstats: report block miner, gas limit and gas consumption 2016-11-29 11:39:56 +02:00
Bas van Kervel
1fc5cc1b59 node: improve error handling for web3_sha3 RPC method 2016-11-29 09:36:51 +01:00
Steven Roose
61ccb43487 core/types: Document Transaction.To (#3366) 2016-11-28 21:56:38 +01:00
Jeffrey Wilcke
bf24b120d7 VERSION, params: bump unstable version 1.5.5 (#3361) 2016-11-28 15:09:12 +01:00
Jeffrey Wilcke
b70acf3c5b params: stable version 1.5.4 (#3360) 2016-11-28 14:59:26 +01:00
bas-vk
b5be6b72cb eth/filter: add support for pending logs (#3219) 2016-11-28 14:59:06 +01:00
Felix Lange
318ad3c1e4 common/hexutil: fix Test{Decode,Unmarshal}Uint64 on 32bit arch (#3363) 2016-11-28 13:55:56 +01:00
Viktor Trón
e949a2ed2f cmd/bzzd: swarm daemon fixes (#3359)
* cmd/bzzd: add missing p2p/discovery flags
* cmd/bzzd: fix two bugs crashing bzzd if bootnodes flag given
* cmd/bzzd: make no swap default, renamed flag bzznoswap->bzzswap
* internal/web3ext: correct methods for bzz IPC module
* cmd/bzzd: ethapi param not mandatory. Warning if no blockchain
* cmd/bzzd: correct default IPC modules in help string
* cmd/utils: fix help description for networkId - add Ropsten
* cmd/bzz, swarm/api, swarm/network: add swarm networkId flag
* cmd/bzzd: change nosync flag to sync and BootTFlag
2016-11-28 13:29:33 +01:00
Péter Szilágyi
8d0108fc5d Merge pull request #3355 from fjl/hexutil-2
Improve hex encoding/decoding
2016-11-28 13:29:16 +02:00
Péter Szilágyi
ba41efa8a0 Merge pull request #3362 from karalabe/cocoapods-fix-3000
build: use single CocoaPods package, pre-release dev builds
2016-11-28 13:28:02 +02:00
Péter Szilágyi
f81660b6db build: use single CocoaPods package, pre-release dev builds 2016-11-28 13:09:43 +02:00
Felix Lange
91bceb4ace ethclient: "addresses" -> "address" in filter query encoding 2016-11-28 11:37:13 +01:00
Felix Lange
be746628c7 eth/filters: simplify query object decoding 2016-11-28 11:37:13 +01:00
Felix Lange
ec5f531f4b accounts: don't use common.Address for address field
common.Address JSON encoding now enforces the 0x prefix, but key files
don't have the prefix.
2016-11-28 11:37:13 +01:00
Felix Lange
37e5816bcd common: use package hexutil for fixed size type encoding 2016-11-28 11:37:13 +01:00
Felföldi Zsolt
665bb43a4c light: implemented VMState.Empty() (#3357) 2016-11-28 11:31:15 +01:00
Viktor Trón
e4bf004560 build/ci: add swarm related executables (bzzd, bzzup, bzzhash) to binary packages (#3354) 2016-11-28 11:25:19 +01:00
Felix Lange
1609df3275 ethclient: use package hexutil for JSON handling 2016-11-28 11:22:52 +01:00
Felix Lange
24f288770e core/types: use package hexutil for JSON handling 2016-11-28 11:22:52 +01:00
Felix Lange
65e6319b12 core/vm: use package hexutil for JSON handling 2016-11-28 11:22:52 +01:00
Felix Lange
ec75953f50 common/hexutil: new package for 0x hex encoding
The new package is purpose-built to handle the encoding consumed and
produced by the RPC API.
2016-11-28 11:22:52 +01:00
Jeffrey Wilcke
801a13f791 core: fixed unwinding bad hash (#3347)
Fixed unwinding of bad hashes when already on the canon chain
2016-11-28 10:37:42 +01:00
Péter Szilágyi
eea8d6aa96 Merge pull request #3356 from fjl/accounts-no-watch-on-windows
accounts: disable file system watcher on windows
2016-11-28 10:36:39 +02:00
Péter Szilágyi
2b9cd71d67 Merge pull request #3352 from fjl/build-git-tag
internal/build: use 'git tag --points-at' to get the current tag
2016-11-28 10:33:12 +02:00
Felix Lange
5df83e3bd9 accounts: disable file system watcher on windows
The watcher is unreliable and causes test failures on Windows.
Disable it until we have a better solution.
2016-11-28 03:09:58 +01:00
Jeffrey Wilcke
6061707371 core: eip unit tests (#3309) 2016-11-28 01:33:28 +01:00
Felix Lange
20899c05a4 internal/build: use 'git tag --points-at' to get the current tag
This should restore support for building with git 1.x.
2016-11-27 18:42:48 +01:00
Péter Szilágyi
4c8c5e2f74 cmd, ethstats, les, mobile, params: native netstats (#3336) 2016-11-25 16:55:06 +01:00
Felix Lange
d1a95c643e Merge pull request #3325 from fjl/p2p-netrestrict
Prevent relay of invalid IPs, add --netrestrict
2016-11-25 13:59:18 +01:00
Péter Szilágyi
9c3ea0d32d Merge pull request #3346 from obscuren/registrar-removal
common/registrar, eth: removed registrar (tech debt)
2016-11-25 14:22:53 +02:00
Jeffrey Wilcke
67e0894d9e common/httpclient, les: removed httpclient 2016-11-25 13:10:44 +01:00
Jeffrey Wilcke
6cc87a31c6 cmd/utils, internal/web3ext: removed httpGet 2016-11-25 12:31:06 +01:00
Jeffrey Wilcke
b8c766a9c5 eth: removed http doc backend api 2016-11-25 12:17:10 +01:00
Péter Szilágyi
66441c9b4b Merge pull request #3345 from karalabe/cleanup-mobile-crossbuilds
Makefile, build: do proper mobile builds, not cross builds
2016-11-25 13:15:57 +02:00
Felix Lange
18d51d1de8 common/registrar: delete the old registrar code
The registrar was broken, unmaintained and there is a much better
replacement: ENS.

(cherry picked from commit 6ca8f57b08)
2016-11-25 12:15:28 +01:00
Felix Lange
01d5fc670b internal/web3ext: remove registrar-related extensions
(cherry picked from commit d54ad55c60)
2016-11-25 12:15:12 +01:00
Péter Szilágyi
0f1cbfd3da Makefile, build: do proper mobile builds, not cross builds 2016-11-25 12:51:10 +02:00
Felix Lange
586f10ecb1 cmd/utils, VERSION: 1.5.4 unstable 2016-11-24 23:06:25 +01:00
Felix Lange
978737f5d5 cmd/utils: 1.5.3 stable 2016-11-24 23:03:13 +01:00
Felix Lange
fa0e057f8a Merge pull request #3341 from obscuren/touch-delete-fix
core, core/state: fixed consensus issue added touch revert
2016-11-24 23:01:34 +01:00
Felix Lange
bca7bfa927 tests: update from github.com/ethereum/tests @ f21c49dc816e 2016-11-24 22:54:50 +01:00
Jeffrey Wilcke
12d654a6fc core, core/state: fixed consensus issue added touch revert
Implemented proper touch revert journal entries and copied a Parity
consensus bug in order to remain in sync with the current longest chain.
2016-11-24 22:12:54 +01:00
Péter Szilágyi
8e64e4383c Merge pull request #3338 from karalabe/miner-driveby-cleanup
miner: remove dead code, add gas price getter
2016-11-24 15:35:38 +02:00
Péter Szilágyi
f59d8cde26 Merge pull request #3337 from karalabe/core-driveby-cleanup
core: remove dead event
2016-11-24 15:34:51 +02:00
Péter Szilágyi
94c0519be2 miner: remove dead code, add gas price getter 2016-11-24 15:24:49 +02:00
Péter Szilágyi
529c502876 core: remove dead event 2016-11-24 15:23:01 +02:00
Jeffrey Wilcke
c04c8f10f0 core: improved bad block error reporting (#3320) 2016-11-23 13:32:25 +01:00
Péter Szilágyi
e05d35e6e0 Merge pull request #3317 from fjl/build-unstable-simplify
build, internal/build: simplify unstable build checks
2016-11-23 12:24:28 +02:00
Felix Lange
e1e2df656a internal/build: add support for git tag in local Environment
I didn't add this initially because the command I tried was too slow.
The 'git for-each-ref ...' invocation takes 40ms on my machine. That
ought to be acceptable.
2016-11-23 10:40:22 +01:00
Péter Szilágyi
f7da5b29f0 Merge pull request #3327 from karalabe/cocoapods-version-round2
build: remove hash metadata from cocoapod version
2016-11-23 11:32:49 +02:00
Péter Szilágyi
2b4c236773 build: remove hash metadata from cocoapod version 2016-11-23 10:49:25 +02:00
Jeffrey Wilcke
a8ca75738a core: implemented new ropsten testnet 2016-11-23 09:34:01 +01:00
Jeffrey Wilcke
aad4890082 cmd/geth, core, light, mobile: removed state account StartingNonce
All account's nonce start at 0.
2016-11-23 09:34:01 +01:00
Felix Lange
e5edd3b983 cmd/bootnode, cmd/geth, cmd/bzzd: add --netrestrict 2016-11-22 22:21:18 +01:00
Felix Lange
a47341cf96 p2p, p2p/discover, p2p/discv5: add IP network restriction feature
The p2p packages can now be configured to restrict all communication to
a certain subset of IP networks. This feature is meant to be used for
private networks.
2016-11-22 22:21:18 +01:00
Felix Lange
e46bda5093 swarm/network: prevent relay of invalid IPs 2016-11-22 22:21:18 +01:00
Felix Lange
a98d1d67d6 p2p/discover, p2p/discv5: prevent relay of invalid IPs and low ports
The discovery DHT contains a number of hosts with LAN and loopback IPs.
These get relayed because some implementations do not perform any checks
on the IP.

go-ethereum already prevented relay in most cases because it verifies
that the host actually exists before adding it to the local table. But
this verification causes other issues. We have received several reports
where people's VPSs got shut down by hosting providers because sending
packets to random LAN hosts is indistinguishable from a slow port scan.

The new check prevents sending random packets to LAN by discarding LAN
IPs sent by Internet hosts (and loopback IPs from LAN and Internet
hosts). The new check also blacklists almost all currently registered
special-purpose networks assigned by IANA to avoid inciting random
responses from services in the LAN.

As another precaution against abuse of the DHT, ports below 1024 are now
considered invalid.
2016-11-22 22:21:18 +01:00
Felix Lange
ba2884f343 p2p/discover, p2p/discv5: use netutil.IsTemporaryError 2016-11-22 22:21:15 +01:00
Felix Lange
1d80155d5e p2p/netutil: new package for network utilities
The new package contains three things for now:

- IP network list parsing and matching
- The WSAEMSGSIZE workaround, which is duplicated in p2p/discover and
  p2p/discv5.
2016-11-22 22:20:38 +01:00
Péter Szilágyi
a0e42aa4e2 build: mobile CI fixes (#3322)
* build: use metatags on cocoapods, not prerelease tags
* build: fix Maven and CocoaPods author email addresses
2016-11-22 17:35:49 +01:00
Felix Lange
92959cd4ef appveyor: use native 32bit go
This simplifies the build and should speed it up a bit because the
standard library doesn't need to be cross compiled on the 32bit builder.
2016-11-21 12:22:55 +01:00
sandakersmann
2c802399c3 README: Changed http:// to https:// for swarm link (#3312)
Changed http:// to https:// on one link in README.md
2016-11-20 19:40:59 +01:00
Felix Lange
8ed72a8470 build: simplify unstable build check
ci.go decides whether a build is unstable by looking at the branch and
tag. This causes issues when a GitHub release is created on the master
branch because the build is considered unstable (the CI environment
reports the branch as "master").

Fix this by looking at the tag only. Any tagged build is stable.
2016-11-18 19:55:19 +01:00
Aron Fischer
0d9a8207d6 cmd/bzzup: trim directory in the manifest entry path (#3299) 2016-11-18 14:41:37 +01:00
FrankWang
04edbb0703 node: Remove redundant filepath.Join in parsePersistentNodes (#3300) 2016-11-18 12:45:06 +01:00
Nick Johnson
e1c1fce92c cmd/utils, VERSION: 1.5.3 unstable (#3306) 2016-11-18 12:33:47 +01:00
Nick Johnson
c8695209f6 core: Don't perform EIP150 hash check on uncles (#3303) 2016-11-18 12:01:54 +01:00
Nick Johnson
9b95112a2d cmd/utils: Set version string to stable (#3304) 2016-11-18 11:57:48 +01:00
Viktor Trón
a602c57c8d README: add documentation for bzz related executables to the table (#3294) 2016-11-18 11:56:27 +01:00
Péter Szilágyi
f3228592f5 travis: dash of black magic to summon the cache daemon (#3288) 2016-11-17 16:15:17 +01:00
Nick Johnson
87b8254da1 Dockerfile: Add git dependency to Dockerfile (#3295) 2016-11-17 15:38:14 +01:00
Felix Lange
20eab80189 cmd/utils, VERSION: 1.5.2 unstable 2016-11-17 14:40:32 +01:00
Jeffrey Wilcke
810389c07a Merge pull request #3278 from obscuren/version-1-5-1
utils: bump stable 1.5.1
2016-11-16 13:10:03 +01:00
Jeffrey Wilcke
3badd3782b Merge pull request #3280 from fjl/fix-go15
build: set GO15VENDOREXPERIMENT in env.sh
2016-11-16 13:07:44 +01:00
Felix Lange
be2a264915 build: set GO15VENDOREXPERIMENT in env.sh
This should fix the 'make' build with Go 1.5.
2016-11-16 10:54:05 +01:00
Jeffrey Wilcke
b81baf5423 utils: bump stable 2016-11-16 10:46:22 +01:00
Péter Szilágyi
64359c9417 cmd/utils, mobile, params: set the correct field on testnet EIP 155 (#3272) 2016-11-16 00:46:40 +01:00
Péter Szilágyi
5a3853f83f travis: only install the needed three android platforms (#3274) 2016-11-16 00:44:37 +01:00
Péter Szilágyi
532d746036 Merge pull request #3275 from obscuren/les-print-fix
les: fixed logging
2016-11-16 00:08:47 +02:00
Jeffrey Wilcke
c66e18b175 Merge pull request #3271 from Arachnid/dockerfiles
Dockerfile revamp
2016-11-15 22:54:51 +01:00
Jeffrey Wilcke
2d4bd3b3ad les: fixed logging 2016-11-15 22:48:00 +01:00
Felix Lange
a96d6c68e2 cmd/utils: remove jit flag handling (#3273)
The jit config options are not handled, but random selection still took
place, printing confusing messages.
2016-11-15 22:20:18 +01:00
Nick Johnson
504815091f containers/docker: Fix dockerfiles for new branch layout; add dockerfile in root 2016-11-15 17:57:56 +00:00
Péter Szilágyi
4dd3e7fe35 Merge pull request #3270 from fjl/version-1.5.1
README, VERSION: update for 1.5 release
2016-11-15 16:56:29 +02:00
Felix Lange
4c614909ff README: update for develop->master switch, remove old build table 2016-11-15 15:53:35 +01:00
Felix Lange
b0a23c73cf VERSION: bump unstable version to 1.5.1 2016-11-15 15:46:51 +01:00
Jeffrey Wilcke
922c1f8f9f Merge pull request #3260 from obscuren/version-1-5-1
utils: unstable 1.5.1
2016-11-15 14:33:14 +01:00
Jeffrey Wilcke
fd27393df3 utils: unstable 1.5.1 2016-11-15 00:40:40 +01:00
2868 changed files with 474431 additions and 2603556 deletions

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
**/.git
.git
!.git/HEAD
!.git/refs/heads
**/*_test.go
build/_workspace
build/_bin
tests/testdata

11
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,11 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
accounts/usbwallet @karalabe
consensus @karalabe
core/ @karalabe @holiman
eth/ @karalabe
les/ @zsfelfoldi
light/ @zsfelfoldi
mobile/ @karalabe
p2p/ @fjl @zsfelfoldi

View File

@@ -2,16 +2,14 @@
Before you do a feature request please check and make sure that it isn't possible
through some other means. The JavaScript enabled console is a powerful feature
in the right hands. Please check our [Bitchin' tricks](https://github.com/ethereum/go-ethereum/wiki/bitchin-tricks) wiki page for more info
in the right hands. Please check our [Wiki page](https://github.com/ethereum/go-ethereum/wiki) for more info
and help.
## Contributing
If you'd like to contribute to go-ethereum please fork, fix, commit and
send a pull request. Commits which 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.
are ignored (use gofmt!).
See [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
for more details on configuring your environment, testing, and

View File

@@ -1,3 +1,9 @@
Hi there,
please note that this is an issue tracker reserved for bug reports and feature requests.
For general questions please use the gitter channel or the Ethereum stack exchange at https://ethereum.stackexchange.com.
#### System information
Geth version: `geth version`

17
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 366
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 42
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

12
.gitignore vendored
View File

@@ -30,3 +30,15 @@ build/_vendor/pkg
# travis
profile.tmp
profile.cov
# IdeaIDE
.idea
# VS Code
.vscode
# dashboard
/dashboard/assets/flow-typed
/dashboard/assets/node_modules
/dashboard/assets/stats.json
/dashboard/assets/bundle.js

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "tests"]
path = tests/testdata
url = https://github.com/ethereum/tests

View File

@@ -65,11 +65,12 @@ Enrique Fynn <enriquefynn@gmail.com>
Vincent G <caktux@gmail.com>
RJ Catalano <rj@erisindustries.com>
RJ Catalano <catalanor0220@gmail.com>
RJ Catalano <catalanor0220@gmail.com> <rj@erisindustries.com>
Nchinda Nchinda <nchinda2@gmail.com>
Aron Fischer <homotopycolimit@users.noreply.github.com>
Aron Fischer <github@aron.guru> <homotopycolimit@users.noreply.github.com>
Vlad Gluhovsky <gluk256@users.noreply.github.com>
@@ -90,3 +91,33 @@ Nick Johnson <arachnid@notdot.net>
Henning Diedrich <hd@eonblast.com>
Henning Diedrich <hd@eonblast.com> Drake Burroughs <wildfyre@hotmail.com>
Felix Lange <fjl@twurst.com>
Felix Lange <fjl@twurst.com> <fjl@users.noreply.github.com>
Максим Чусовлянов <mchusovlianov@gmail.com>
Louis Holbrook <dev@holbrook.no>
Louis Holbrook <dev@holbrook.no> <nolash@users.noreply.github.com>
Thomas Bocek <tom@tomp2p.net>
Victor Tran <vu.tran54@gmail.com>
Justin Drake <drakefjustin@gmail.com>
Frank Wang <eternnoir@gmail.com>
Gary Rong <garyrong0905@gmail.com>
Guillaume Nicolas <guin56@gmail.com>
Sorin Neacsu <sorin.neacsu@gmail.com>
Sorin Neacsu <sorin.neacsu@gmail.com> <sorin@users.noreply.github.com>
Valentin Wüstholz <wuestholz@gmail.com>
Valentin Wüstholz <wuestholz@gmail.com> <wuestholz@users.noreply.github.com>
Armin Braun <me@obrown.io>
Ernesto del Toro <ernesto.deltoro@gmail.com>
Ernesto del Toro <ernesto.deltoro@gmail.com> <ernestodeltoro@users.noreply.github.com>

View File

@@ -5,26 +5,58 @@ matrix:
include:
- os: linux
dist: trusty
go: 1.5.4
env:
- GO15VENDOREXPERIMENT=1
sudo: required
go: 1.8.x
script:
- sudo modprobe fuse
- sudo chmod 666 /dev/fuse
- sudo chown root:$USER /etc/fuse.conf
- go run build/ci.go install
- go run build/ci.go test -coverage
# These are the latest Go versions.
- os: linux
dist: trusty
go: 1.6.2
- os: linux
dist: trusty
go: 1.7
sudo: required
go: 1.9.x
script:
- sudo modprobe fuse
- sudo chmod 666 /dev/fuse
- sudo chown root:$USER /etc/fuse.conf
- go run build/ci.go install
- go run build/ci.go test -coverage
- os: osx
go: 1.7
go: 1.9.x
script:
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
- brew update
- brew install caskroom/cask/brew-cask
- brew cask install osxfuse
- go run build/ci.go install
- go run build/ci.go test -coverage
# This builder only tests code linters on latest version of Go
- os: linux
dist: trusty
go: 1.9.x
env:
- lint
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go lint
# This builder does the Ubuntu PPA and Linux Azure uploads
- os: linux
dist: trusty
sudo: required
go: 1.7
go: 1.9.x
env:
- ubuntu-ppa
- azure-linux
git:
submodules: false # avoid cloning ethereum/tests
addons:
apt:
packages:
@@ -32,6 +64,7 @@ matrix:
- debhelper
- dput
- gcc-multilib
- fakeroot
script:
# Build for the primary platforms that Trusty can manage
- go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum
@@ -44,54 +77,118 @@ matrix:
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
- sudo ln -s /usr/include/asm-generic /usr/include/asm
- GOARM=5 CC=arm-linux-gnueabi-gcc go run build/ci.go install -arch arm
- GOARM=5 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
- GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- GOARM=6 CC=arm-linux-gnueabi-gcc go run build/ci.go install -arch arm
- GOARM=6 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
- GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- GOARM=7 CC=arm-linux-gnueabihf-gcc go run build/ci.go install -arch arm
- GOARM=7 go run build/ci.go install -arch arm -cc arm-linux-gnueabihf-gcc
- GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
- go run build/ci.go install -arch arm64 -cc aarch64-linux-gnu-gcc
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
# This builder does the Linux Azure MIPS xgo uploads
- os: linux
dist: trusty
services:
- docker
go: 1.9.x
env:
- azure-linux-mips
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go xgo --alltools -- --targets=linux/mips --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips; do mv -f "${bin}" "${bin/-linux-mips/}"; done
- go run build/ci.go archive -arch mips -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mipsle --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mipsle; do mv -f "${bin}" "${bin/-linux-mipsle/}"; done
- go run build/ci.go archive -arch mipsle -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mips64 --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips64; do mv -f "${bin}" "${bin/-linux-mips64/}"; done
- go run build/ci.go archive -arch mips64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mips64le --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips64le; do mv -f "${bin}" "${bin/-linux-mips64le/}"; done
- go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# This builder does the Android Maven and Azure uploads
- os: linux
dist: precise # Needed for the android tools
addons:
apt:
packages:
- oracle-java8-installer
- oracle-java8-set-default
language: android
android:
components:
- platform-tools
- tools
- android-15
- android-19
- android-24
env:
- azure-android
- maven-android
git:
submodules: false # avoid cloning ethereum/tests
before_install:
- curl https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz | tar -xz
- export PATH=`pwd`/go/bin:$PATH
- export GOROOT=`pwd`/go
- export GOPATH=$HOME/go
script:
# Build the Android archive and upload it to Maven Central and Azure
- curl https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip -o android-ndk-r15c.zip
- unzip -q android-ndk-r15c.zip && rm android-ndk-r15c.zip
- mv android-ndk-r15c $HOME
- export ANDROID_NDK=$HOME/android-ndk-r15c
- mkdir -p $GOPATH/src/github.com/ethereum
- ln -s `pwd` $GOPATH/src/github.com/ethereum
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
- os: osx
go: 1.7
go: 1.9.x
env:
- azure-osx
- mobile
cache:
directories:
- $HOME/.android.platforms
- $HOME/.cocoapods
- azure-ios
- cocoapods-ios
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go install
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
# Build the Android archive and upload it to Maven Central and Azure
- brew update
- brew install android-sdk maven gpg
- alias gpg="gpg2"
- export ANDROID_HOME=/usr/local/opt/android-sdk
- mkdir -p $ANDROID_HOME/platforms
- mv -f $HOME/.android.platforms $ANDROID_HOME/platforms
- echo "y" | android update sdk --no-ui --filter platform
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
- mv -f $ANDROID_HOME/platforms $HOME/.android.platforms
# Build the iOS framework and upload it to CocoaPods and Azure
- gem uninstall cocoapods -a
- gem install cocoapods --pre
- gem uninstall cocoapods -a -x
- gem install cocoapods
- mv ~/.cocoapods/repos/master ~/.cocoapods/repos/master.bak
- sed -i '.bak' 's/repo.join/!repo.join/g' $(dirname `gem which cocoapods`)/cocoapods/sources_manager.rb
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git clone --depth=1 https://github.com/CocoaPods/Specs.git ~/.cocoapods/repos/master && pod setup --verbose; fi
- xctool -version
- xcrun simctl list
- travis_wait 30 go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
install:
- go get golang.org/x/tools/cmd/cover
script:
- go run build/ci.go install
- go run build/ci.go test -coverage -vet
# Workaround for https://github.com/golang/go/issues/23749
- export CGO_CFLAGS_ALLOW='-fmodules|-fblocks|-fobjc-arc'
- go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
# This builder does the Azure archive purges to avoid accumulating junk
- os: linux
dist: trusty
sudo: required
go: 1.9.x
env:
- azure-purge
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go purge -store gethstore/builds -days 14
notifications:
webhooks:

114
AUTHORS
View File

@@ -1,63 +1,173 @@
# This is the official list of go-ethereum authors for copyright purposes.
Afri Schoedon <5chdn@users.noreply.github.com>
Agustin Armellini Fischer <armellini13@gmail.com>
Airead <fgh1987168@gmail.com>
Alan Chen <alanchchen@users.noreply.github.com>
Alejandro Isaza <alejandro.isaza@gmail.com>
Ales Katona <ales@coinbase.com>
Alex Leverington <alex@ethdev.com>
Alex Wu <wuyiding@gmail.com>
Alexandre Van de Sande <alex.vandesande@ethdev.com>
Aron Fischer <homotopycolimit@users.noreply.github.com>
Ali Hajimirza <Ali92hm@users.noreply.github.com>
Anton Evangelatov <anton.evangelatov@gmail.com>
Arba Sasmoyo <arba.sasmoyo@gmail.com>
Armani Ferrante <armaniferrante@berkeley.edu>
Armin Braun <me@obrown.io>
Aron Fischer <github@aron.guru>
Bas van Kervel <bas@ethdev.com>
Benjamin Brent <benjamin@benjaminbrent.com>
Benoit Verkindt <benoit.verkindt@gmail.com>
Bo <bohende@gmail.com>
Bo Ye <boy.e.computer.1982@outlook.com>
Bob Glickstein <bobg@users.noreply.github.com>
Brian Schroeder <bts@gmail.com>
Casey Detrio <cdetrio@gmail.com>
Chase Wright <mysticryuujin@gmail.com>
Christoph Jentzsch <jentzsch.software@gmail.com>
Daniel A. Nagy <nagy.da@gmail.com>
Daniel Sloof <goapsychadelic@gmail.com>
Darrel Herbst <dherbst@gmail.com>
Dave Appleton <calistralabs@gmail.com>
Diego Siqueira <DiSiqueira@users.noreply.github.com>
Dmitry Shulyak <yashulyak@gmail.com>
Egon Elbre <egonelbre@gmail.com>
Elias Naur <elias.naur@gmail.com>
Elliot Shepherd <elliot@identitii.com>
Enrique Fynn <enriquefynn@gmail.com>
Ernesto del Toro <ernesto.deltoro@gmail.com>
Ethan Buchman <ethan@coinculture.info>
Eugene Valeyev <evgen.povt@gmail.com>
Evangelos Pappas <epappas@evalonlabs.com>
Evgeny Danilenko <6655321@bk.ru>
Fabian Vogelsteller <fabian@frozeman.de>
Fabio Barone <fabio.barone.co@gmail.com>
Fabio Berger <fabioberger1991@gmail.com>
FaceHo <facehoshi@gmail.com>
Felix Lange <fjl@twurst.com>
Fiisio <liangcszzu@163.com>
Frank Wang <eternnoir@gmail.com>
Furkan KAMACI <furkankamaci@gmail.com>
Gary Rong <garyrong0905@gmail.com>
George Ornbo <george@shapeshed.com>
Gregg Dourgarian <greggd@tempworks.com>
Guillaume Ballet <gballet@gmail.com>
Guillaume Nicolas <guin56@gmail.com>
Gustav Simonsson <gustav.simonsson@gmail.com>
Hao Bryan Cheng <haobcheng@gmail.com>
Henning Diedrich <hd@eonblast.com>
Isidoro Ghezzi <isidoro.ghezzi@icloud.com>
Ivan Daniluk <ivan.daniluk@gmail.com>
Jae Kwon <jkwon.work@gmail.com>
Jamie Pitts <james.pitts@gmail.com>
Janoš Guljaš <janos@users.noreply.github.com>
Jason Carver <jacarver@linkedin.com>
Jay Guo <guojiannan1101@gmail.com>
Jeff R. Allen <jra@nella.org>
Jeffrey Wilcke <jeffrey@ethereum.org>
Jens Agerberg <github@agerberg.me>
Jia Chenhui <jiachenhui1989@gmail.com>
Jim McDonald <Jim@mcdee.net>
Joel Burget <joelburget@gmail.com>
Jonathan Brown <jbrown@bluedroplet.com>
Joseph Chow <ethereum@outlook.com>
Justin Clark-Casey <justincc@justincc.org>
Justin Drake <drakefjustin@gmail.com>
Kenji Siu <kenji@isuntv.com>
Kobi Gurkan <kobigurk@gmail.com>
Konrad Feldmeier <konrad@brainbot.com>
Kurkó Mihály <kurkomisi@users.noreply.github.com>
Kyuntae Ethan Kim <ethan.kyuntae.kim@gmail.com>
Lefteris Karapetsas <lefteris@refu.co>
Leif Jurvetson <leijurv@gmail.com>
Leo Shklovskii <leo@thermopylae.net>
Lewis Marshall <lewis@lmars.net>
Lio李欧 <lionello@users.noreply.github.com>
Louis Holbrook <dev@holbrook.no>
Luca Zeug <luclu@users.noreply.github.com>
Magicking <s@6120.eu>
Maran Hidskes <maran.hidskes@gmail.com>
Marek Kotewicz <marek.kotewicz@gmail.com>
Mark <markya0616@gmail.com>
Martin Holst Swende <martin@swende.se>
Matthew Di Ferrante <mattdf@users.noreply.github.com>
Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
Maximilian Meister <mmeister@suse.de>
Micah Zoltu <micah@zoltu.net>
Michael Ruminer <michael.ruminer+github@gmail.com>
Miguel Mota <miguelmota2@gmail.com>
Miya Chen <miyatlchen@gmail.com>
Nchinda Nchinda <nchinda2@gmail.com>
Nick Dodson <silentcicero@outlook.com>
Nick Johnson <arachnid@notdot.net>
Nicolas Guillaume <gunicolas@sqli.com>
Noman <noman@noman.land>
Oli Bye <olibye@users.noreply.github.com>
Paul Litvak <litvakpol@012.net.il>
Paulo L F Casaretto <pcasaretto@gmail.com>
Paweł Bylica <chfast@gmail.com>
Peter Pratscher <pratscher@gmail.com>
Petr Mikusek <petr@mikusek.info>
Péter Szilágyi <peterke@gmail.com>
RJ Catalano <rj@erisindustries.com>
RJ Catalano <catalanor0220@gmail.com>
Ramesh Nair <ram@hiddentao.com>
Ricardo Catalinas Jiménez <r@untroubled.be>
Ricardo Domingos <ricardohsd@gmail.com>
Richard Hart <richardhart92@gmail.com>
Rob <robert@rojotek.com>
Robert Zaremba <robert.zaremba@scale-it.pl>
Russ Cox <rsc@golang.org>
Rémy Roy <remyroy@remyroy.com>
S. Matthew English <s-matthew-english@users.noreply.github.com>
Shintaro Kaneko <kaneshin0120@gmail.com>
Sorin Neacsu <sorin.neacsu@gmail.com>
Stein Dekker <dekker.stein@gmail.com>
Steve Waldman <swaldman@mchange.com>
Steven Roose <stevenroose@gmail.com>
Taylor Gerring <taylor.gerring@gmail.com>
Thomas Bocek <tom@tomp2p.net>
Ti Zhou <tizhou1986@gmail.com>
Tosh Camille <tochecamille@gmail.com>
Valentin Wüstholz <wuestholz@gmail.com>
Victor Farazdagi <simple.square@gmail.com>
Victor Tran <vu.tran54@gmail.com>
Viktor Trón <viktor.tron@gmail.com>
Ville Sundell <github@solarius.fi>
Vincent G <caktux@gmail.com>
Vitalik Buterin <v@buterin.com>
Vitaly V <vvelikodny@gmail.com>
Vivek Anand <vivekanand1101@users.noreply.github.com>
Vlad Gluhovsky <gluk256@users.noreply.github.com>
Yohann Léon <sybiload@gmail.com>
Yoichi Hirai <i@yoichihirai.com>
Yondon Fu <yondon.fu@gmail.com>
Zach <zach.ramsay@gmail.com>
Zahoor Mohamed <zahoor@zahoor.in>
Zoe Nolan <github@zoenolan.org>
Zsolt Felföldi <zsfelfoldi@gmail.com>
am2rican5 <am2rican5@gmail.com>
ayeowch <ayeowch@gmail.com>
b00ris <b00ris@mail.ru>
bailantaotao <Edwin@maicoin.com>
baizhenxuan <nkbai@163.com>
bloonfield <bloonfield@163.com>
changhong <changhong.yu@shanbay.com>
evgk <evgeniy.kamyshev@gmail.com>
ferhat elmas <elmas.ferhat@gmail.com>
holisticode <holistic.computing@gmail.com>
jtakalai <juuso.takalainen@streamr.com>
ken10100147 <sunhongping@kanjian.com>
ligi <ligi@ligi.de>
mark.lin <mark@maicoin.com>
necaremus <necaremus@gmail.com>
njupt-moon <1015041018@njupt.edu.cn>
nkbai <nkbai@163.com>
rhaps107 <dod-source@yandex.ru>
slumber1122 <slumber1122@gmail.com>
sunxiaojun2014 <sunxiaojun-xy@360.cn>
terasum <terasum@163.com>
tsarpaul <Litvakpol@012.net.il>
xiekeyang <xiekeyang@users.noreply.github.com>
yoza <yoza.is12s@gmail.com>
ΞTHΞЯSPHΞЯΞ <{viktor.tron,nagydani,zsfelfoldi}@gmail.com>
Максим Чусовлянов <mchusovlianov@gmail.com>

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
# Build Geth in a stock Go builder container
FROM golang:1.9-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers
ADD . /go-ethereum
RUN cd /go-ethereum && make geth
# Pull Geth into a second stage deploy alpine container
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
EXPOSE 8545 8546 30303 30303/udp 30304/udp
ENTRYPOINT ["geth"]

15
Dockerfile.alltools Normal file
View File

@@ -0,0 +1,15 @@
# Build Geth in a stock Go builder container
FROM golang:1.9-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers
ADD . /go-ethereum
RUN cd /go-ethereum && make all
# Pull all binaries into a second stage deploy alpine container
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
EXPOSE 8545 8546 30303 30303/udp 30304/udp

View File

@@ -2,14 +2,13 @@
# with Go source code. If you know what GOPATH is then you probably
# don't need to bother with make.
.PHONY: geth geth-cross evm all test clean
.PHONY: geth android ios geth-cross swarm evm all test clean
.PHONY: geth-linux geth-linux-386 geth-linux-amd64 geth-linux-mips64 geth-linux-mips64le
.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
.PHONY: geth-android geth-ios
GOBIN = build/bin
GOBIN = $(shell pwd)/build/bin
GO ?= latest
geth:
@@ -17,20 +16,43 @@ geth:
@echo "Done building."
@echo "Run \"$(GOBIN)/geth\" to launch geth."
evm:
build/env.sh go run build/ci.go install ./cmd/evm
swarm:
build/env.sh go run build/ci.go install ./cmd/swarm
@echo "Done building."
@echo "Run \"$(GOBIN)/evm to start the evm."
@echo "Run \"$(GOBIN)/swarm\" to launch swarm."
all:
build/env.sh go run build/ci.go install
android:
build/env.sh go run build/ci.go aar --local
@echo "Done building."
@echo "Import \"$(GOBIN)/geth.aar\" to use the library."
ios:
build/env.sh go run build/ci.go xcode --local
@echo "Done building."
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
test: all
build/env.sh go run build/ci.go test
clean:
rm -fr build/_workspace/pkg/ $(GOBIN)/*
# The devtools target installs tools required for 'go generate'.
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
devtools:
env GOBIN= go get -u golang.org/x/tools/cmd/stringer
env GOBIN= go get -u github.com/kevinburke/go-bindata/go-bindata
env GOBIN= go get -u github.com/fjl/gencodec
env GOBIN= go get -u github.com/golang/protobuf/protoc-gen-go
env GOBIN= go install ./cmd/abigen
@type "npm" 2> /dev/null || echo 'Please install node.js and npm'
@type "solc" 2> /dev/null || echo 'Please install solc'
@type "protoc" 2> /dev/null || echo 'Please install protoc'
# Cross Compilation Targets (xgo)
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
@@ -42,12 +64,12 @@ geth-linux: geth-linux-386 geth-linux-amd64 geth-linux-arm geth-linux-mips64 get
@ls -ld $(GOBIN)/geth-linux-*
geth-linux-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/386 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/386 -v ./cmd/geth
@echo "Linux 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep 386
geth-linux-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/amd64 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/amd64 -v ./cmd/geth
@echo "Linux amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep amd64
@@ -56,32 +78,42 @@ geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-ar
@ls -ld $(GOBIN)/geth-linux-* | grep arm
geth-linux-arm-5:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-5 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-5 -v ./cmd/geth
@echo "Linux ARMv5 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-5
geth-linux-arm-6:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-6 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-6 -v ./cmd/geth
@echo "Linux ARMv6 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-6
geth-linux-arm-7:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-7 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm-7 -v ./cmd/geth
@echo "Linux ARMv7 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm-7
geth-linux-arm64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/arm64 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/arm64 -v ./cmd/geth
@echo "Linux ARM64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep arm64
geth-linux-mips:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips --ldflags '-extldflags "-static"' -v ./cmd/geth
@echo "Linux MIPS cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips
geth-linux-mipsle:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mipsle --ldflags '-extldflags "-static"' -v ./cmd/geth
@echo "Linux MIPSle cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mipsle
geth-linux-mips64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/mips64 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64 --ldflags '-extldflags "-static"' -v ./cmd/geth
@echo "Linux MIPS64 cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips64
geth-linux-mips64le:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=linux/mips64le -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=linux/mips64le --ldflags '-extldflags "-static"' -v ./cmd/geth
@echo "Linux MIPS64le cross compilation done:"
@ls -ld $(GOBIN)/geth-linux-* | grep mips64le
@@ -90,12 +122,12 @@ geth-darwin: geth-darwin-386 geth-darwin-amd64
@ls -ld $(GOBIN)/geth-darwin-*
geth-darwin-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=darwin/386 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/386 -v ./cmd/geth
@echo "Darwin 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-* | grep 386
geth-darwin-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=darwin/amd64 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=darwin/amd64 -v ./cmd/geth
@echo "Darwin amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-darwin-* | grep amd64
@@ -104,21 +136,11 @@ geth-windows: geth-windows-386 geth-windows-amd64
@ls -ld $(GOBIN)/geth-windows-*
geth-windows-386:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=windows/386 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/386 -v ./cmd/geth
@echo "Windows 386 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep 386
geth-windows-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=windows/amd64 -v ./cmd/geth
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/geth
@echo "Windows amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep amd64
geth-android:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=android-21/aar -v ./cmd/geth
@echo "Android cross compilation done:"
@ls -ld $(GOBIN)/geth-android-*
geth-ios:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --dest=$(GOBIN) --targets=ios-7.0/framework -v ./cmd/geth
@echo "iOS framework cross compilation done:"
@ls -ld $(GOBIN)/geth-ios-*

108
README.md
View File

@@ -1,28 +1,16 @@
## Ethereum Go
## Go Ethereum
Official golang implementation of the Ethereum protocol
| Linux | OSX | ARM | Windows | Tests
----------|---------|-----|-----|---------|------
develop | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](https://build.ethdev.com/builders/Linux%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](https://build.ethdev.com/builders/OSX%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=ARM%20Go%20develop%20branch)](https://build.ethdev.com/builders/ARM%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20Go%20develop%20branch)](https://build.ethdev.com/builders/Windows%20Go%20develop%20branch/builds/-1) | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=develop)](https://travis-ci.org/ethereum/go-ethereum) [![codecov.io](https://codecov.io/github/ethereum/go-ethereum/coverage.svg?branch=develop)](https://codecov.io/github/ethereum/go-ethereum?branch=develop)
master | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20master%20branch)](https://build.ethdev.com/builders/Linux%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20Go%20master%20branch)](https://build.ethdev.com/builders/OSX%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=ARM%20Go%20master%20branch)](https://build.ethdev.com/builders/ARM%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20Go%20master%20branch)](https://build.ethdev.com/builders/Windows%20Go%20master%20branch/builds/-1) | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) [![codecov.io](https://codecov.io/github/ethereum/go-ethereum/coverage.svg?branch=master)](https://codecov.io/github/ethereum/go-ethereum?branch=master)
Official golang implementation of the Ethereum protocol.
[![API Reference](
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://godoc.org/github.com/ethereum/go-ethereum)
[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
## Automated development builds
The following builds are built automatically by our build servers after each push to the [develop](https://github.com/ethereum/go-ethereum/tree/develop) branch.
* [Docker](https://registry.hub.docker.com/u/ethereum/client-go/)
* [OS X](https://build.ethdev.com/builds/OSX%20Go%20develop%20branch/Mist-OSX-latest.dmg)
* Ubuntu
[trusty](https://build.ethdev.com/builds/Linux%20Go%20develop%20deb%20i386-trusty/latest/) |
[utopic](https://build.ethdev.com/builds/Linux%20Go%20develop%20deb%20i386-utopic/latest/)
* [Windows 64-bit](https://build.ethdev.com/builds/Windows%20Go%20develop%20branch/Geth-Win64-latest.zip)
* [ARM](https://build.ethdev.com/builds/ARM%20Go%20develop%20branch/geth-ARM-latest.tar.bz2)
Automated builds are available for stable releases and the unstable master branch.
Binary archives are published at https://geth.ethereum.org/downloads/.
## Building the source
@@ -30,7 +18,7 @@ For prerequisites and detailed build instructions please read the
[Installation Instructions](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum)
on the wiki.
Building geth requires both a Go and a C compiler.
Building geth requires both a Go (version 1.7 or later) and a C compiler.
You can install them using your favourite package manager.
Once the dependencies are installed, run
@@ -46,13 +34,14 @@ The go-ethereum project comes with several wrappers/executables found in the `cm
| Command | Description |
|:----------:|-------------|
| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default) archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. Please see our [Command Line Options](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) wiki page for details. |
| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default) archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) for command line options. |
| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. |
| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. |
| `disasm` | Bytecode disassembler to convert EVM (Ethereum Virtual Machine) bytecode into more user friendly assembly-like opcodes (e.g. `echo "6001" | disasm`). For details on the individual opcodes, please see pages 22-30 of the [Ethereum Yellow Paper](http://gavwood.com/paper.pdf). |
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. |
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
| `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. |
| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. |
## Running geth
@@ -69,21 +58,19 @@ the user doesn't care about years-old historical data, so we can fast-sync quick
state of the network. To do so:
```
$ geth --fast --cache=512 console
$ geth console
```
This command will:
* Start geth in fast sync mode (`--fast`), causing it to download more data in exchange for avoiding
processing the entire history of the Ethereum network, which is very CPU intensive.
* Bump the memory allowance of the database to 512MB (`--cache=512`), which can help significantly in
sync times especially for HDD users. This flag is optional and you can set it as high or as low as
you'd like, though we'd recommend the 512MB - 2GB range.
* Start geth in fast sync mode (default, can be changed with the `--syncmode` flag), causing it to
download more data in exchange for avoiding processing the entire history of the Ethereum network,
which is very CPU intensive.
* Start up Geth's built-in interactive [JavaScript console](https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console),
(via the trailing `console` subcommand) through which you can invoke all official [`web3` methods](https://github.com/ethereum/wiki/wiki/JavaScript-API)
as well as Geth's own [management APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs).
This too is optional and if you leave it out you can always attach to an already running Geth instance
with `geth --attach`.
with `geth attach`.
### Full node on the Ethereum test network
@@ -93,25 +80,50 @@ entire system. In other words, instead of attaching to the main network, you wan
network with your node, which is fully equivalent to the main network, but with play-Ether only.
```
$ geth --testnet --fast --cache=512 console
$ geth --testnet console
```
The `--fast`, `--cache` flags and `console` subcommand have the exact same meaning as above and they
are equially useful on the testnet too. Please see above for their explanations if you've skipped to
here.
The `console` subcommand have the exact same meaning as above and they are equally useful on the
testnet too. Please see above for their explanations if you've skipped to here.
Specifying the `--testnet` flag however will reconfigure your Geth instance a bit:
* Instead of using the default data directory (`~/.ethereum` on Linux for example), Geth will nest
itself one level deeper into a `testnet` subfolder (`~/.ethereum/testnet` on Linux).
itself one level deeper into a `testnet` subfolder (`~/.ethereum/testnet` on Linux). Note, on OSX
and Linux this also means that attaching to a running testnet node requires the use of a custom
endpoint since `geth attach` will try to attach to a production node endpoint by default. E.g.
`geth attach <datadir>/testnet/geth.ipc`. Windows users are not affected by this.
* Instead of connecting the main Ethereum network, the client will connect to the test network,
which uses different P2P bootnodes, different network IDs and genesis states.
*Note: Although there are some internal protective measures to prevent transactions from crossing
over between the main network and test network (different starting nonces), you should make sure to
always use separate accounts for play-money and real-money. Unless you manually move accounts, Geth
will by default correctly separate the two networks and will not make any accounts available between
them.*
over between the main network and test network, you should make sure to always use separate accounts
for play-money and real-money. Unless you manually move accounts, Geth will by default correctly
separate the two networks and will not make any accounts available between them.*
### Full node on the Rinkeby test network
The above test network is a cross client one based on the ethash proof-of-work consensus algorithm. As such, it has certain extra overhead and is more susceptible to reorganization attacks due to the network's low difficulty / security. Go Ethereum also supports connecting to a proof-of-authority based test network called [*Rinkeby*](https://www.rinkeby.io) (operated by members of the community). This network is lighter, more secure, but is only supported by go-ethereum.
```
$ geth --rinkeby console
```
### Configuration
As an alternative to passing the numerous flags to the `geth` binary, you can also pass a configuration file via:
```
$ geth --config /path/to/your_config.toml
```
To get an idea how the file should look like you can use the `dumpconfig` subcommand to export your existing configuration:
```
$ geth --your-favourite-flags dumpconfig
```
*Note: This works only with geth v1.6.0 and above.*
#### Docker quick start
@@ -120,10 +132,12 @@ One of the quickest ways to get Ethereum up and running on your machine is by us
```
docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \
-p 8545:8545 -p 30303:30303 \
ethereum/client-go --fast --cache=512
ethereum/client-go
```
This will start geth in fast sync mode with a DB memory allowance of 512MB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image.
This will start geth in fast-sync mode with a DB memory allowance of 1GB just as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image.
Do not forget `--rpcaddr 0.0.0.0`, if you want to access RPC from other containers and/or hosts. By default, `geth` binds to the local interface and RPC endpoints is not accessible from the outside.
### Programatically interfacing Geth nodes
@@ -131,7 +145,7 @@ As a developer, sooner rather than later you'll want to start interacting with G
network via your own programs and not manually through the console. To aid this, Geth has built in
support for a JSON-RPC based APIs ([standard APIs](https://github.com/ethereum/wiki/wiki/JSON-RPC) and
[Geth specific APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs)). These can be
exposed via HTTP, WebSockets and IPC (unix sockets on unix based platroms, and named pipes on Windows).
exposed via HTTP, WebSockets and IPC (unix sockets on unix based platforms, and named pipes on Windows).
The IPC interface is enabled by default and exposes all the APIs supported by Geth, whereas the HTTP
and WS interfaces need to manually be enabled and only expose a subset of APIs due to security reasons.
@@ -174,6 +188,12 @@ and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`)
```json
{
"config": {
"chainId": 0,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
@@ -253,7 +273,7 @@ instance for mining, run it with all your usual flags, extended by:
$ geth <usual-flags> --mine --minerthreads=1 --etherbase=0x0000000000000000000000000000000000000000
```
Which will start mining bocks and transactions on a single CPU thread, crediting all proceedings to
Which will start mining blocks and transactions on a single CPU thread, crediting all proceedings to
the account specified by `--etherbase`. You can further tune the mining by changing the default gas
limit blocks converge to (`--targetgaslimit`) and the price transactions are accepted at (`--gasprice`).
@@ -273,7 +293,7 @@ Please make sure your contributions adhere to our coding guidelines:
* Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
* Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
* Pull requests need to be based on and opened against the `develop` branch.
* Pull requests need to be based on and opened against the `master` branch.
* Commit messages should be prefixed with the package(s) they modify.
* E.g. "eth, rpc: make trace configs optional"

View File

@@ -1 +1 @@
1.5.0
1.8.2

View File

@@ -17,14 +17,10 @@
package abi
import (
"bytes"
"encoding/json"
"fmt"
"io"
"math/big"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/common"
)
// The ABI holds information about a contract's context and available
@@ -55,302 +51,55 @@ func JSON(reader io.Reader) (ABI, error) {
// methods string signature. (signature = baz(uint32,string32))
func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
// Fetch the ABI of the requested method
var method Method
if name == "" {
method = abi.Constructor
} else {
m, exist := abi.Methods[name]
if !exist {
return nil, fmt.Errorf("method '%s' not found", name)
// constructor
arguments, err := abi.Constructor.Inputs.Pack(args...)
if err != nil {
return nil, err
}
method = m
return arguments, nil
}
arguments, err := method.pack(method, args...)
method, exist := abi.Methods[name]
if !exist {
return nil, fmt.Errorf("method '%s' not found", name)
}
arguments, err := method.Inputs.Pack(args...)
if err != nil {
return nil, err
}
// Pack up the method ID too if not a constructor and return
if name == "" {
return arguments, nil
}
return append(method.Id(), arguments...), nil
}
// toGoSliceType parses the input and casts it to the proper slice defined by the ABI
// argument in T.
func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
index := i * 32
// The slice must, at very least be large enough for the index+32 which is exactly the size required
// for the [offset in output, size of offset].
if index+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), index+32)
}
elem := t.Type.Elem
// first we need to create a slice of the type
var refSlice reflect.Value
switch elem.T {
case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int.
refSlice = reflect.ValueOf([]*big.Int(nil))
case AddressTy: // address must be of slice Address
refSlice = reflect.ValueOf([]common.Address(nil))
case HashTy: // hash must be of slice hash
refSlice = reflect.ValueOf([]common.Hash(nil))
case FixedBytesTy:
refSlice = reflect.ValueOf([][]byte(nil))
default: // no other types are supported
return nil, fmt.Errorf("abi: unsupported slice type %v", elem.T)
}
var slice []byte
var size int
var offset int
if t.Type.IsSlice {
// get the offset which determines the start of this array ...
offset = int(common.BytesToBig(output[index : index+32]).Uint64())
if offset+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
}
slice = output[offset:]
// ... starting with the size of the array in elements ...
size = int(common.BytesToBig(slice[:32]).Uint64())
slice = slice[32:]
// ... and make sure that we've at the very least the amount of bytes
// available in the buffer.
if size*32 > len(slice) {
return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32)
}
// reslice to match the required size
slice = slice[:(size * 32)]
} else if t.Type.IsArray {
//get the number of elements in the array
size = t.Type.SliceSize
//check to make sure array size matches up
if index+32*size > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), index+32*size)
}
//slice is there for a fixed amount of times
slice = output[index : index+size*32]
}
for i := 0; i < size; i++ {
var (
inter interface{} // interface type
returnOutput = slice[i*32 : i*32+32] // the return output
)
// set inter to the correct type (cast)
switch elem.T {
case IntTy, UintTy:
inter = common.BytesToBig(returnOutput)
case BoolTy:
inter = common.BytesToBig(returnOutput).Uint64() > 0
case AddressTy:
inter = common.BytesToAddress(returnOutput)
case HashTy:
inter = common.BytesToHash(returnOutput)
case FixedBytesTy:
inter = returnOutput
}
// append the item to our reflect slice
refSlice = reflect.Append(refSlice, reflect.ValueOf(inter))
}
// return the interface
return refSlice.Interface(), nil
}
// toGoType parses the input and casts it to the proper type defined by the ABI
// argument in T.
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
// we need to treat slices differently
if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy {
return toGoSlice(i, t, output)
}
index := i * 32
if index+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32)
}
// Parse the given index output and check whether we need to read
// a different offset and length based on the type (i.e. string, bytes)
var returnOutput []byte
switch t.Type.T {
case StringTy, BytesTy: // variable arrays are written at the end of the return bytes
// parse offset from which we should start reading
offset := int(common.BytesToBig(output[index : index+32]).Uint64())
if offset+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32)
}
// parse the size up until we should be reading
size := int(common.BytesToBig(output[offset : offset+32]).Uint64())
if offset+32+size > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+size)
}
// get the bytes for this return value
returnOutput = output[offset+32 : offset+32+size]
default:
returnOutput = output[index : index+32]
}
// convert the bytes to whatever is specified by the ABI.
switch t.Type.T {
case IntTy, UintTy:
bigNum := common.BytesToBig(returnOutput)
// If the type is a integer convert to the integer type
// specified by the ABI.
switch t.Type.Kind {
case reflect.Uint8:
return uint8(bigNum.Uint64()), nil
case reflect.Uint16:
return uint16(bigNum.Uint64()), nil
case reflect.Uint32:
return uint32(bigNum.Uint64()), nil
case reflect.Uint64:
return uint64(bigNum.Uint64()), nil
case reflect.Int8:
return int8(bigNum.Int64()), nil
case reflect.Int16:
return int16(bigNum.Int64()), nil
case reflect.Int32:
return int32(bigNum.Int64()), nil
case reflect.Int64:
return int64(bigNum.Int64()), nil
case reflect.Ptr:
return bigNum, nil
}
case BoolTy:
return common.BytesToBig(returnOutput).Uint64() > 0, nil
case AddressTy:
return common.BytesToAddress(returnOutput), nil
case HashTy:
return common.BytesToHash(returnOutput), nil
case BytesTy, FixedBytesTy:
return returnOutput, nil
case StringTy:
return string(returnOutput), nil
}
return nil, fmt.Errorf("abi: unknown type %v", t.Type.T)
}
// these variable are used to determine certain types during type assertion for
// assignment.
var (
r_interSlice = reflect.TypeOf([]interface{}{})
r_hash = reflect.TypeOf(common.Hash{})
r_bytes = reflect.TypeOf([]byte{})
r_byte = reflect.TypeOf(byte(0))
)
// Unpack output in v according to the abi specification
func (abi ABI) Unpack(v interface{}, name string, output []byte) error {
var method = abi.Methods[name]
func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) {
if len(output) == 0 {
return fmt.Errorf("abi: unmarshalling empty output")
}
// make sure the passed value is a pointer
valueOf := reflect.ValueOf(v)
if reflect.Ptr != valueOf.Kind() {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
// since there can't be naming collisions with contracts and events,
// we need to decide whether we're calling a method or an event
if method, ok := abi.Methods[name]; ok {
if len(output)%32 != 0 {
return fmt.Errorf("abi: improperly formatted output")
}
return method.Outputs.Unpack(v, output)
} else if event, ok := abi.Events[name]; ok {
return event.Inputs.Unpack(v, output)
}
var (
value = valueOf.Elem()
typ = value.Type()
)
if len(method.Outputs) > 1 {
switch value.Kind() {
// struct will match named return values to the struct's field
// names
case reflect.Struct:
for i := 0; i < len(method.Outputs); i++ {
marshalledValue, err := toGoType(i, method.Outputs[i], output)
if err != nil {
return err
}
reflectValue := reflect.ValueOf(marshalledValue)
for j := 0; j < typ.NumField(); j++ {
field := typ.Field(j)
// TODO read tags: `abi:"fieldName"`
if field.Name == strings.ToUpper(method.Outputs[i].Name[:1])+method.Outputs[i].Name[1:] {
if err := set(value.Field(j), reflectValue, method.Outputs[i]); err != nil {
return err
}
}
}
}
case reflect.Slice:
if !value.Type().AssignableTo(r_interSlice) {
return fmt.Errorf("abi: cannot marshal tuple in to slice %T (only []interface{} is supported)", v)
}
// if the slice already contains values, set those instead of the interface slice itself.
if value.Len() > 0 {
if len(method.Outputs) > value.Len() {
return fmt.Errorf("abi: cannot marshal in to slices of unequal size (require: %v, got: %v)", len(method.Outputs), value.Len())
}
for i := 0; i < len(method.Outputs); i++ {
marshalledValue, err := toGoType(i, method.Outputs[i], output)
if err != nil {
return err
}
reflectValue := reflect.ValueOf(marshalledValue)
if err := set(value.Index(i).Elem(), reflectValue, method.Outputs[i]); err != nil {
return err
}
}
return nil
}
// create a new slice and start appending the unmarshalled
// values to the new interface slice.
z := reflect.MakeSlice(typ, 0, len(method.Outputs))
for i := 0; i < len(method.Outputs); i++ {
marshalledValue, err := toGoType(i, method.Outputs[i], output)
if err != nil {
return err
}
z = reflect.Append(z, reflect.ValueOf(marshalledValue))
}
value.Set(z)
default:
return fmt.Errorf("abi: cannot unmarshal tuple in to %v", typ)
}
} else {
marshalledValue, err := toGoType(0, method.Outputs[0], output)
if err != nil {
return err
}
if err := set(value, reflect.ValueOf(marshalledValue), method.Outputs[0]); err != nil {
return err
}
}
return nil
return fmt.Errorf("abi: could not locate named method or event")
}
// UnmarshalJSON implements json.Unmarshaler interface
func (abi *ABI) UnmarshalJSON(data []byte) error {
var fields []struct {
Type string
Name string
Constant bool
Indexed bool
Inputs []Argument
Outputs []Argument
Type string
Name string
Constant bool
Anonymous bool
Inputs []Argument
Outputs []Argument
}
if err := json.Unmarshal(data, &fields); err != nil {
@@ -375,11 +124,23 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
}
case "event":
abi.Events[field.Name] = Event{
Name: field.Name,
Inputs: field.Inputs,
Name: field.Name,
Anonymous: field.Anonymous,
Inputs: field.Inputs,
}
}
}
return nil
}
// MethodById looks up a method by the 4-byte id
// returns nil if none found
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
for _, method := range abi.Methods {
if bytes.Equal(method.Id(), sigdata[:4]) {
return &method, nil
}
}
return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,8 @@ package abi
import (
"encoding/json"
"fmt"
"reflect"
"strings"
)
// Argument holds the name of the argument and the corresponding type.
@@ -29,21 +31,250 @@ type Argument struct {
Indexed bool // indexed is only used by events
}
func (a *Argument) UnmarshalJSON(data []byte) error {
type Arguments []Argument
// UnmarshalJSON implements json.Unmarshaler interface
func (argument *Argument) UnmarshalJSON(data []byte) error {
var extarg struct {
Name string
Type string
Name string
Type string
Indexed bool
}
err := json.Unmarshal(data, &extarg)
if err != nil {
return fmt.Errorf("argument json err: %v", err)
}
a.Type, err = NewType(extarg.Type)
argument.Type, err = NewType(extarg.Type)
if err != nil {
return err
}
a.Name = extarg.Name
argument.Name = extarg.Name
argument.Indexed = extarg.Indexed
return nil
}
// LengthNonIndexed returns the number of arguments when not counting 'indexed' ones. Only events
// can ever have 'indexed' arguments, it should always be false on arguments for method input/output
func (arguments Arguments) LengthNonIndexed() int {
out := 0
for _, arg := range arguments {
if !arg.Indexed {
out++
}
}
return out
}
// NonIndexed returns the arguments with indexed arguments filtered out
func (arguments Arguments) NonIndexed() Arguments {
var ret []Argument
for _, arg := range arguments {
if !arg.Indexed {
ret = append(ret, arg)
}
}
return ret
}
// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[]
func (arguments Arguments) isTuple() bool {
return len(arguments) > 1
}
// Unpack performs the operation hexdata -> Go format
func (arguments Arguments) Unpack(v interface{}, data []byte) error {
// make sure the passed value is arguments pointer
if reflect.Ptr != reflect.ValueOf(v).Kind() {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
}
marshalledValues, err := arguments.UnpackValues(data)
if err != nil {
return err
}
if arguments.isTuple() {
return arguments.unpackTuple(v, marshalledValues)
}
return arguments.unpackAtomic(v, marshalledValues)
}
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
var (
value = reflect.ValueOf(v).Elem()
typ = value.Type()
kind = value.Kind()
)
if err := requireUnpackKind(value, typ, kind, arguments); err != nil {
return err
}
// If the output interface is a struct, make sure names don't collide
if kind == reflect.Struct {
exists := make(map[string]bool)
for _, arg := range arguments {
field := capitalise(arg.Name)
if field == "" {
return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
}
if exists[field] {
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
}
exists[field] = true
}
}
for i, arg := range arguments.NonIndexed() {
reflectValue := reflect.ValueOf(marshalledValues[i])
switch kind {
case reflect.Struct:
name := capitalise(arg.Name)
for j := 0; j < typ.NumField(); j++ {
// TODO read tags: `abi:"fieldName"`
if typ.Field(j).Name == name {
if err := set(value.Field(j), reflectValue, arg); err != nil {
return err
}
}
}
case reflect.Slice, reflect.Array:
if value.Len() < i {
return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len())
}
v := value.Index(i)
if err := requireAssignable(v, reflectValue); err != nil {
return err
}
if err := set(v.Elem(), reflectValue, arg); err != nil {
return err
}
default:
return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ)
}
}
return nil
}
// unpackAtomic unpacks ( hexdata -> go ) a single value
func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error {
if len(marshalledValues) != 1 {
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
}
elem := reflect.ValueOf(v).Elem()
reflectValue := reflect.ValueOf(marshalledValues[0])
return set(elem, reflectValue, arguments.NonIndexed()[0])
}
// Computes the full size of an array;
// i.e. counting nested arrays, which count towards size for unpacking.
func getArraySize(arr *Type) int {
size := arr.Size
// Arrays can be nested, with each element being the same size
arr = arr.Elem
for arr.T == ArrayTy {
// Keep multiplying by elem.Size while the elem is an array.
size *= arr.Size
arr = arr.Elem
}
// Now we have the full array size, including its children.
return size
}
// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
// without supplying a struct to unpack into. Instead, this method returns a list containing the
// values. An atomic argument will be a list with one element.
func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
retval := make([]interface{}, 0, arguments.LengthNonIndexed())
virtualArgs := 0
for index, arg := range arguments.NonIndexed() {
marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data)
if arg.Type.T == ArrayTy {
// If we have a static array, like [3]uint256, these are coded as
// just like uint256,uint256,uint256.
// This means that we need to add two 'virtual' arguments when
// we count the index from now on.
//
// Array values nested multiple levels deep are also encoded inline:
// [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256
//
// Calculate the full array size to get the correct offset for the next argument.
// Decrement it by 1, as the normal index increment is still applied.
virtualArgs += getArraySize(&arg.Type) - 1
}
if err != nil {
return nil, err
}
retval = append(retval, marshalledValue)
}
return retval, nil
}
// PackValues performs the operation Go format -> Hexdata
// It is the semantic opposite of UnpackValues
func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) {
return arguments.Pack(args...)
}
// Pack performs the operation Go format -> Hexdata
func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
// Make sure arguments match up and pack them
abiArgs := arguments
if len(args) != len(abiArgs) {
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs))
}
// variable input is the output appended at the end of packed
// output. This is used for strings and bytes types input.
var variableInput []byte
// input offset is the bytes offset for packed output
inputOffset := 0
for _, abiArg := range abiArgs {
if abiArg.Type.T == ArrayTy {
inputOffset += 32 * abiArg.Type.Size
} else {
inputOffset += 32
}
}
var ret []byte
for i, a := range args {
input := abiArgs[i]
// pack the input
packed, err := input.Type.pack(reflect.ValueOf(a))
if err != nil {
return nil, err
}
// check for a slice type (string, bytes, slice)
if input.Type.requiresLengthPrefix() {
// calculate the offset
offset := inputOffset + len(variableInput)
// set the offset
ret = append(ret, packNum(reflect.ValueOf(offset))...)
// Append the packed output to the variable input. The variable input
// will be appended at the end of the input.
variableInput = append(variableInput, packed...)
} else {
// append the packed value to the input
ret = append(ret, packed...)
}
}
// append the variable input at the end of the packed input
ret = append(ret, variableInput...)
return ret, nil
}
// capitalise makes the first character of a string upper case, also removing any
// prefixing underscores from the variable names.
func capitalise(input string) string {
for len(input) > 0 && input[0] == '_' {
input = input[1:]
}
if len(input) == 0 {
return ""
}
return strings.ToUpper(input[:1]) + input[1:]
}

View File

@@ -22,7 +22,7 @@ import (
"io"
"io/ioutil"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
@@ -35,7 +35,7 @@ func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) {
if err != nil {
return nil, err
}
key, err := accounts.DecryptKey(json, passphrase)
key, err := keystore.DecryptKey(json, passphrase)
if err != nil {
return nil, err
}
@@ -52,7 +52,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
if address != keyAddr {
return nil, errors.New("not authorized to sign this account")
}
signature, err := crypto.SignEthereum(signer.Hash(tx).Bytes(), key)
signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key)
if err != nil {
return nil, err
}

View File

@@ -17,13 +17,13 @@
package bind
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"golang.org/x/net/context"
)
var (
@@ -52,12 +52,6 @@ type ContractCaller interface {
CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
}
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
type DeployBackend interface {
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
}
// PendingContractCaller defines methods to perform contract calls on the pending state.
// Call will try to discover this interface when access to the pending state is requested.
// If the backend does not support the pending state, Call returns ErrNoPendingState.
@@ -85,13 +79,34 @@ type ContractTransactor interface {
// There is no guarantee that this is the true gas limit requirement as other
// transactions may be added or removed by miners, but it should provide a basis
// for setting a reasonable default.
EstimateGas(ctx context.Context, call ethereum.CallMsg) (usedGas *big.Int, err error)
EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error)
// SendTransaction injects the transaction into the pending pool for execution.
SendTransaction(ctx context.Context, tx *types.Transaction) error
}
// ContractFilterer defines the methods needed to access log events using one-off
// queries or continuous event subscriptions.
type ContractFilterer interface {
// FilterLogs executes a log filter operation, blocking during execution and
// returning all the results in one batch.
//
// TODO(karalabe): Deprecate when the subscription one can return past data too.
FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error)
// SubscribeFilterLogs creates a background log filtering operation, returning
// a subscription immediately, which can be used to stream the found events.
SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
}
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
type DeployBackend interface {
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
}
// ContractBackend defines the methods needed to work with contracts on a read-write basis.
type ContractBackend interface {
ContractCaller
ContractTransactor
ContractFilterer
}

View File

@@ -17,31 +17,35 @@
package backends
import (
"context"
"errors"
"fmt"
"math/big"
"sync"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"golang.org/x/net/context"
"github.com/ethereum/go-ethereum/rpc"
)
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
var chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block")
var errGasEstimationFailed = errors.New("gas required exceeds allowance or always failing transaction")
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
// the background. Its main purpose is to allow easily testing contract bindings.
@@ -53,16 +57,25 @@ type SimulatedBackend struct {
pendingBlock *types.Block // Currently pending block that will be imported on request
pendingState *state.StateDB // Currently pending state that will be the active on on request
events *filters.EventSystem // Event system for filtering log events live
config *params.ChainConfig
}
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
// for testing purposes.
func NewSimulatedBackend(accounts ...core.GenesisAccount) *SimulatedBackend {
func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
database, _ := ethdb.NewMemDatabase()
core.WriteGenesisBlockForTesting(database, accounts...)
blockchain, _ := core.NewBlockChain(database, chainConfig, new(core.FakePow), new(event.TypeMux))
backend := &SimulatedBackend{database: database, blockchain: blockchain}
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, Alloc: alloc}
genesis.MustCommit(database)
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{})
backend := &SimulatedBackend{
database: database,
blockchain: blockchain,
config: genesis.Config,
events: filters.NewEventSystem(new(event.TypeMux), &filterBackend{database, blockchain}, false),
}
backend.rollback()
return backend
}
@@ -88,9 +101,11 @@ func (b *SimulatedBackend) Rollback() {
}
func (b *SimulatedBackend) rollback() {
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
statedb, _ := b.blockchain.State()
b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
}
// CodeAt returns the code associated with a certain account in the blockchain.
@@ -144,7 +159,8 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres
// TransactionReceipt returns the receipt of a transaction.
func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
return core.GetReceipt(b.database, txHash), nil
receipt, _, _, _ := core.GetReceipt(b.database, txHash)
return receipt, nil
}
// PendingCodeAt returns the code associated with an account in the pending state.
@@ -167,7 +183,7 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM
if err != nil {
return nil, err
}
rval, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
return rval, err
}
@@ -177,7 +193,7 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu
defer b.mu.Unlock()
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
rval, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
return rval, err
}
@@ -198,37 +214,80 @@ func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error
// EstimateGas executes the requested code against the currently pending block/state and
// returns the used amount of gas.
func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (*big.Int, error) {
func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) {
b.mu.Lock()
defer b.mu.Unlock()
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
_, gas, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
return gas, err
// Determine the lowest and highest possible gas limits to binary search in between
var (
lo uint64 = params.TxGas - 1
hi uint64
cap uint64
)
if call.Gas >= params.TxGas {
hi = call.Gas
} else {
hi = b.pendingBlock.GasLimit()
}
cap = hi
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) bool {
call.Gas = gas
snapshot := b.pendingState.Snapshot()
_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
b.pendingState.RevertToSnapshot(snapshot)
if err != nil || failed {
return false
}
return true
}
// Execute the binary search and hone in on an executable gas limit
for lo+1 < hi {
mid := (hi + lo) / 2
if !executable(mid) {
lo = mid
} else {
hi = mid
}
}
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap {
if !executable(hi) {
return 0, errGasEstimationFailed
}
}
return hi, nil
}
// callContract implemens common code between normal and pending contract calls.
// callContract implements common code between normal and pending contract calls.
// state is modified during execution, make sure to copy it if necessary.
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, *big.Int, error) {
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) {
// Ensure message is initialized properly.
if call.GasPrice == nil {
call.GasPrice = big.NewInt(1)
}
if call.Gas == nil || call.Gas.BitLen() == 0 {
call.Gas = big.NewInt(50000000)
if call.Gas == 0 {
call.Gas = 50000000
}
if call.Value == nil {
call.Value = new(big.Int)
}
// Set infinite balance to the fake caller account.
from := statedb.GetOrNewStateObject(call.From)
from.SetBalance(common.MaxBig)
from.SetBalance(math.MaxBig256)
// Execute the call.
msg := callmsg{call}
vmenv := core.NewEnv(statedb, chainConfig, b.blockchain, msg, block.Header(), vm.Config{})
gaspool := new(core.GasPool).AddGas(common.MaxBig)
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
return ret, gasUsed, err
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
gaspool := new(core.GasPool).AddGas(math.MaxUint64)
return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
}
// SendTransaction updates the pending block to include the given transaction.
@@ -246,14 +305,96 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
}
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() {
block.AddTx(tx)
}
block.AddTx(tx)
})
statedb, _ := b.blockchain.State()
b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
return nil
}
// FilterLogs executes a log filter operation, blocking during execution and
// returning all the results in one batch.
//
// TODO(karalabe): Deprecate when the subscription one can return past data too.
func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) {
// Initialize unset filter boundaried to run from genesis to chain head
from := int64(0)
if query.FromBlock != nil {
from = query.FromBlock.Int64()
}
to := int64(-1)
if query.ToBlock != nil {
to = query.ToBlock.Int64()
}
// Construct and execute the filter
filter := filters.New(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics)
logs, err := filter.Logs(ctx)
if err != nil {
return nil, err
}
res := make([]types.Log, len(logs))
for i, log := range logs {
res[i] = *log
}
return res, nil
}
// SubscribeFilterLogs creates a background log filtering operation, returning a
// subscription immediately, which can be used to stream the found events.
func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
// Subscribe to contract events
sink := make(chan []*types.Log)
sub, err := b.events.SubscribeLogs(query, sink)
if err != nil {
return nil, err
}
// Since we're getting logs in batches, we need to flatten them into a plain stream
return event.NewSubscription(func(quit <-chan struct{}) error {
defer sub.Unsubscribe()
for {
select {
case logs := <-sink:
for _, log := range logs {
select {
case ch <- *log:
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
}), nil
}
// AdjustTime adds a time shift to the simulated clock.
func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
b.mu.Lock()
defer b.mu.Unlock()
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() {
block.AddTx(tx)
}
block.OffsetTime(int64(adjustment.Seconds()))
})
statedb, _ := b.blockchain.State()
b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
return nil
}
@@ -267,6 +408,60 @@ func (m callmsg) Nonce() uint64 { return 0 }
func (m callmsg) CheckNonce() bool { return false }
func (m callmsg) To() *common.Address { return m.CallMsg.To }
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas }
func (m callmsg) Gas() uint64 { return m.CallMsg.Gas }
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
func (m callmsg) Data() []byte { return m.CallMsg.Data }
// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.
type filterBackend struct {
db ethdb.Database
bc *core.BlockChain
}
func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db }
func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) {
if block == rpc.LatestBlockNumber {
return fb.bc.CurrentHeader(), nil
}
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
}
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil
}
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
receipts := core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash))
if receipts == nil {
return nil, nil
}
logs := make([][]*types.Log, len(receipts))
for i, receipt := range receipts {
logs[i] = receipt.Logs
}
return logs, nil
}
func (fb *filterBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
return event.NewSubscription(func(quit <-chan struct{}) error {
<-quit
return nil
})
}
func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return fb.bc.SubscribeChainEvent(ch)
}
func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
return fb.bc.SubscribeRemovedLogsEvent(ch)
}
func (fb *filterBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return fb.bc.SubscribeLogsEvent(ch)
}
func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 }
func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) {
panic("not supported")
}

View File

@@ -17,6 +17,7 @@
package bind
import (
"context"
"errors"
"fmt"
"math/big"
@@ -26,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"golang.org/x/net/context"
"github.com/ethereum/go-ethereum/event"
)
// SignerFn is a signer function callback when a contract requires a method to
@@ -35,7 +36,8 @@ type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Tra
// CallOpts is the collection of options to fine tune a contract call request.
type CallOpts struct {
Pending bool // Whether to operate on the pending state or the last known one
Pending bool // Whether to operate on the pending state or the last known one
From common.Address // Optional the sender address, otherwise the first account is used
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
}
@@ -49,11 +51,27 @@ type TransactOpts struct {
Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds)
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
GasLimit *big.Int // Gas limit to set for the transaction execution (nil = estimate + 10%)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
}
// FilterOpts is the collection of options to fine tune filtering for events
// within a bound contract.
type FilterOpts struct {
Start uint64 // Start of the queried range
End *uint64 // End of the range (nil = latest)
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
}
// WatchOpts is the collection of options to fine tune subscribing for events
// within a bound contract.
type WatchOpts struct {
Start *uint64 // Start of the queried range (nil = latest)
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
}
// BoundContract is the base wrapper object that reflects a contract on the
// Ethereum network. It contains a collection of methods that are used by the
// higher level contract bindings to operate.
@@ -62,16 +80,18 @@ type BoundContract struct {
abi abi.ABI // Reflect based ABI to access the correct Ethereum methods
caller ContractCaller // Read interface to interact with the blockchain
transactor ContractTransactor // Write interface to interact with the blockchain
filterer ContractFilterer // Event filtering to interact with the blockchain
}
// NewBoundContract creates a low level contract interface through which calls
// and transactions may be made through.
func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller, transactor ContractTransactor) *BoundContract {
func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller, transactor ContractTransactor, filterer ContractFilterer) *BoundContract {
return &BoundContract{
address: address,
abi: abi,
caller: caller,
transactor: transactor,
filterer: filterer,
}
}
@@ -79,7 +99,7 @@ func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller
// deployment address with a Go wrapper.
func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) {
// Otherwise try to deploy the contract
c := NewBoundContract(common.Address{}, abi, backend, backend)
c := NewBoundContract(common.Address{}, abi, backend, backend, backend)
input, err := c.abi.Pack("", params...)
if err != nil {
@@ -108,7 +128,7 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
return err
}
var (
msg = ethereum.CallMsg{To: &c.address, Data: input}
msg = ethereum.CallMsg{From: opts.From, To: &c.address, Data: input}
ctx = ensureContext(opts.Context)
code []byte
output []byte
@@ -170,7 +190,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
if value == nil {
value = new(big.Int)
}
nonce := uint64(0)
var nonce uint64
if opts.Nonce == nil {
nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
if err != nil {
@@ -188,7 +208,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
}
}
gasLimit := opts.GasLimit
if gasLimit == nil {
if gasLimit == 0 {
// Gas estimation cannot succeed without code for method invocations
if contract != nil {
if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil {
@@ -224,6 +244,104 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
return signedTx, nil
}
// FilterLogs filters contract logs for past blocks, returning the necessary
// channels to construct a strongly typed bound iterator on top of them.
func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) {
// Don't crash on a lazy user
if opts == nil {
opts = new(FilterOpts)
}
// Append the event selector to the query parameters and construct the topic set
query = append([][]interface{}{{c.abi.Events[name].Id()}}, query...)
topics, err := makeTopics(query...)
if err != nil {
return nil, nil, err
}
// Start the background filtering
logs := make(chan types.Log, 128)
config := ethereum.FilterQuery{
Addresses: []common.Address{c.address},
Topics: topics,
FromBlock: new(big.Int).SetUint64(opts.Start),
}
if opts.End != nil {
config.ToBlock = new(big.Int).SetUint64(*opts.End)
}
/* TODO(karalabe): Replace the rest of the method below with this when supported
sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs)
*/
buff, err := c.filterer.FilterLogs(ensureContext(opts.Context), config)
if err != nil {
return nil, nil, err
}
sub, err := event.NewSubscription(func(quit <-chan struct{}) error {
for _, log := range buff {
select {
case logs <- log:
case <-quit:
return nil
}
}
return nil
}), nil
if err != nil {
return nil, nil, err
}
return logs, sub, nil
}
// WatchLogs filters subscribes to contract logs for future blocks, returning a
// subscription object that can be used to tear down the watcher.
func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) {
// Don't crash on a lazy user
if opts == nil {
opts = new(WatchOpts)
}
// Append the event selector to the query parameters and construct the topic set
query = append([][]interface{}{{c.abi.Events[name].Id()}}, query...)
topics, err := makeTopics(query...)
if err != nil {
return nil, nil, err
}
// Start the background filtering
logs := make(chan types.Log, 128)
config := ethereum.FilterQuery{
Addresses: []common.Address{c.address},
Topics: topics,
}
if opts.Start != nil {
config.FromBlock = new(big.Int).SetUint64(*opts.Start)
}
sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs)
if err != nil {
return nil, nil, err
}
return logs, sub, nil
}
// UnpackLog unpacks a retrieved log into the provided output structure.
func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error {
if len(log.Data) > 0 {
if err := c.abi.Unpack(out, event, log.Data); err != nil {
return err
}
}
var indexed abi.Arguments
for _, arg := range c.abi.Events[event].Inputs {
if arg.Indexed {
indexed = append(indexed, arg)
}
}
return parseTopics(out, indexed, log.Topics[1:])
}
// ensureContext is a helper method to ensure a context is not nil, even if the
// user specified it as such.
func ensureContext(ctx context.Context) context.Context {
if ctx == nil {
return context.TODO()

View File

@@ -63,10 +63,11 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
return r
}, abis[i])
// Extract the call and transact methods, and sort them alphabetically
// Extract the call and transact methods; events; and sort them alphabetically
var (
calls = make(map[string]*tmplMethod)
transacts = make(map[string]*tmplMethod)
events = make(map[string]*tmplEvent)
)
for _, original := range evmABI.Methods {
// Normalize the method for capital cases and non-anonymous inputs/outputs
@@ -89,11 +90,33 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
}
// Append the methods to the call or transact lists
if original.Const {
calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original)}
calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
} else {
transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original)}
transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
}
}
for _, original := range evmABI.Events {
// Skip anonymous events as they don't support explicit filtering
if original.Anonymous {
continue
}
// Normalize the event for capital cases and non-anonymous outputs
normalized := original
normalized.Name = methodNormalizer[lang](original.Name)
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
copy(normalized.Inputs, original.Inputs)
for j, input := range normalized.Inputs {
// Indexed fields are input, non-indexed ones are outputs
if input.Indexed {
if input.Name == "" {
normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j)
}
}
}
// Append the event to the accumulator list
events[original.Name] = &tmplEvent{Original: original, Normalized: normalized}
}
contracts[types[i]] = &tmplContract{
Type: capitalise(types[i]),
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
@@ -101,6 +124,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
Constructor: evmABI.Constructor,
Calls: calls,
Transacts: transacts,
Events: events,
}
}
// Generate the contract template data content and render it
@@ -111,10 +135,11 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
buffer := new(bytes.Buffer)
funcs := map[string]interface{}{
"bindtype": bindType[lang],
"namedtype": namedType[lang],
"capitalise": capitalise,
"decapitalise": decapitalise,
"bindtype": bindType[lang],
"bindtopictype": bindTopicType[lang],
"namedtype": namedType[lang],
"capitalise": capitalise,
"decapitalise": decapitalise,
}
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang]))
if err := tmpl.Execute(buffer, data); err != nil {
@@ -122,138 +147,194 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
}
// For Go bindings pass the code through goimports to clean it up and double check
if lang == LangGo {
code, err := imports.Process("", buffer.Bytes(), nil)
code, err := imports.Process(".", buffer.Bytes(), nil)
if err != nil {
return "", fmt.Errorf("%v\n%s", err, buffer)
}
return string(code), nil
}
// For all others just return as is for now
return string(buffer.Bytes()), nil
return buffer.String(), nil
}
// bindType is a set of type binders that convert Solidity types to some supported
// programming language.
// programming language types.
var bindType = map[Lang]func(kind abi.Type) string{
LangGo: bindTypeGo,
LangJava: bindTypeJava,
}
// Helper function for the binding generators.
// It reads the unmatched characters after the inner type-match,
// (since the inner type is a prefix of the total type declaration),
// looks for valid arrays (possibly a dynamic one) wrapping the inner type,
// and returns the sizes of these arrays.
//
// Returned array sizes are in the same order as solidity signatures; inner array size first.
// Array sizes may also be "", indicating a dynamic array.
func wrapArray(stringKind string, innerLen int, innerMapping string) (string, []string) {
remainder := stringKind[innerLen:]
//find all the sizes
matches := regexp.MustCompile(`\[(\d*)\]`).FindAllStringSubmatch(remainder, -1)
parts := make([]string, 0, len(matches))
for _, match := range matches {
//get group 1 from the regex match
parts = append(parts, match[1])
}
return innerMapping, parts
}
// Translates the array sizes to a Go-lang declaration of a (nested) array of the inner type.
// Simply returns the inner type if arraySizes is empty.
func arrayBindingGo(inner string, arraySizes []string) string {
out := ""
//prepend all array sizes, from outer (end arraySizes) to inner (start arraySizes)
for i := len(arraySizes) - 1; i >= 0; i-- {
out += "[" + arraySizes[i] + "]"
}
out += inner
return out
}
// bindTypeGo converts a Solidity type to a Go one. Since there is no clear mapping
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. *big.Int).
func bindTypeGo(kind abi.Type) string {
stringKind := kind.String()
innerLen, innerMapping := bindUnnestedTypeGo(stringKind)
return arrayBindingGo(wrapArray(stringKind, innerLen, innerMapping))
}
// The inner function of bindTypeGo, this finds the inner type of stringKind.
// (Or just the type itself if it is not an array or slice)
// The length of the matched part is returned, with the the translated type.
func bindUnnestedTypeGo(stringKind string) (int, string) {
switch {
case strings.HasPrefix(stringKind, "address"):
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
if len(parts) != 2 {
return stringKind
}
return fmt.Sprintf("%scommon.Address", parts[1])
return len("address"), "common.Address"
case strings.HasPrefix(stringKind, "bytes"):
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
if len(parts) != 3 {
return stringKind
}
return fmt.Sprintf("%s[%s]byte", parts[2], parts[1])
parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind)
return len(parts[0]), fmt.Sprintf("[%s]byte", parts[1])
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
if len(parts) != 4 {
return stringKind
}
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind)
switch parts[2] {
case "8", "16", "32", "64":
return fmt.Sprintf("%s%sint%s", parts[3], parts[1], parts[2])
return len(parts[0]), fmt.Sprintf("%sint%s", parts[1], parts[2])
}
return fmt.Sprintf("%s*big.Int", parts[3])
return len(parts[0]), "*big.Int"
case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"):
parts := regexp.MustCompile("([a-z]+)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
if len(parts) != 3 {
return stringKind
}
return fmt.Sprintf("%s%s", parts[2], parts[1])
case strings.HasPrefix(stringKind, "bool"):
return len("bool"), "bool"
case strings.HasPrefix(stringKind, "string"):
return len("string"), "string"
default:
return stringKind
return len(stringKind), stringKind
}
}
// Translates the array sizes to a Java declaration of a (nested) array of the inner type.
// Simply returns the inner type if arraySizes is empty.
func arrayBindingJava(inner string, arraySizes []string) string {
// Java array type declarations do not include the length.
return inner + strings.Repeat("[]", len(arraySizes))
}
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. BigDecimal).
func bindTypeJava(kind abi.Type) string {
stringKind := kind.String()
innerLen, innerMapping := bindUnnestedTypeJava(stringKind)
return arrayBindingJava(wrapArray(stringKind, innerLen, innerMapping))
}
// The inner function of bindTypeJava, this finds the inner type of stringKind.
// (Or just the type itself if it is not an array or slice)
// The length of the matched part is returned, with the the translated type.
func bindUnnestedTypeJava(stringKind string) (int, string) {
switch {
case strings.HasPrefix(stringKind, "address"):
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 2 {
return stringKind
return len(stringKind), stringKind
}
if parts[1] == "" {
return fmt.Sprintf("Address")
return len("address"), "Address"
}
return fmt.Sprintf("Addresses")
return len(parts[0]), "Addresses"
case strings.HasPrefix(stringKind, "bytes"):
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
if len(parts) != 3 {
return stringKind
parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind)
if len(parts) != 2 {
return len(stringKind), stringKind
}
if parts[2] != "" {
return "byte[][]"
}
return "byte[]"
return len(parts[0]), "byte[]"
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
if len(parts) != 4 {
return stringKind
//Note that uint and int (without digits) are also matched,
// these are size 256, and will translate to BigInt (the default).
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind)
if len(parts) != 3 {
return len(stringKind), stringKind
}
switch parts[2] {
case "8", "16", "32", "64":
if parts[1] == "" {
if parts[3] == "" {
return fmt.Sprintf("int%s", parts[2])
}
return fmt.Sprintf("int%s[]", parts[2])
}
namedSize := map[string]string{
"8": "byte",
"16": "short",
"32": "int",
"64": "long",
}[parts[2]]
//default to BigInt
if namedSize == "" {
namedSize = "BigInt"
}
if parts[3] == "" {
return fmt.Sprintf("BigInt")
}
return fmt.Sprintf("BigInts")
return len(parts[0]), namedSize
case strings.HasPrefix(stringKind, "bool"):
parts := regexp.MustCompile("bool(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
if len(parts) != 2 {
return stringKind
}
if parts[1] == "" {
return fmt.Sprintf("bool")
}
return fmt.Sprintf("bool[]")
return len("bool"), "boolean"
case strings.HasPrefix(stringKind, "string"):
parts := regexp.MustCompile("string(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
if len(parts) != 2 {
return stringKind
}
if parts[1] == "" {
return fmt.Sprintf("String")
}
return fmt.Sprintf("String[]")
return len("string"), "String"
default:
return stringKind
return len(stringKind), stringKind
}
}
// bindTopicType is a set of type binders that convert Solidity types to some
// supported programming language topic types.
var bindTopicType = map[Lang]func(kind abi.Type) string{
LangGo: bindTopicTypeGo,
LangJava: bindTopicTypeJava,
}
// bindTypeGo converts a Solidity topic type to a Go one. It is almost the same
// funcionality as for simple types, but dynamic types get converted to hashes.
func bindTopicTypeGo(kind abi.Type) string {
bound := bindTypeGo(kind)
if bound == "string" || bound == "[]byte" {
bound = "common.Hash"
}
return bound
}
// bindTypeGo converts a Solidity topic type to a Java one. It is almost the same
// funcionality as for simple types, but dynamic types get converted to hashes.
func bindTopicTypeJava(kind abi.Type) string {
bound := bindTypeJava(kind)
if bound == "String" || bound == "Bytes" {
bound = "Hash"
}
return bound
}
// namedType is a set of functions that transform language specific types to
// named versions that my be used inside method names.
var namedType = map[Lang]func(string, abi.Type) string{
@@ -273,12 +354,14 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
return "String"
case "string[]":
return "Strings"
case "bool":
case "boolean":
return "Bool"
case "bool[]":
case "boolean[]":
return "Bools"
case "BigInt":
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(solKind.String())
case "BigInt[]":
return "BigInts"
default:
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String())
if len(parts) != 4 {
return javaKind
}
@@ -292,8 +375,6 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
default:
return javaKind
}
default:
return javaKind
}
}
@@ -304,8 +385,15 @@ var methodNormalizer = map[Lang]func(string) string{
LangJava: decapitalise,
}
// capitalise makes the first character of a string upper case.
// capitalise makes the first character of a string upper case, also removing any
// prefixing underscores from the variable names.
func capitalise(input string) string {
for len(input) > 0 && input[0] == '_' {
input = input[1:]
}
if len(input) == 0 {
return ""
}
return strings.ToUpper(input[:1]) + input[1:]
}
@@ -314,16 +402,25 @@ func decapitalise(input string) string {
return strings.ToLower(input[:1]) + input[1:]
}
// structured checks whether a method has enough information to return a proper
// Go struct ot if flat returns are needed.
func structured(method abi.Method) bool {
if len(method.Outputs) < 2 {
// structured checks whether a list of ABI data types has enough information to
// operate through a proper Go struct or if flat returns are needed.
func structured(args abi.Arguments) bool {
if len(args) < 2 {
return false
}
for _, out := range method.Outputs {
exists := make(map[string]bool)
for _, out := range args {
// If the name is anonymous, we can't organize into a struct
if out.Name == "" {
return false
}
// If the field name is empty when normalized or collides (var, Var, _var, _Var),
// we can't organize into a struct
field := capitalise(out.Name)
if field == "" || exists[field] {
return false
}
exists[field] = true
}
return true
}

View File

@@ -126,6 +126,7 @@ var bindTests = []struct {
{"type":"function","name":"namedOutput","constant":true,"inputs":[],"outputs":[{"name":"str","type":"string"}]},
{"type":"function","name":"anonOutput","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"}]},
{"type":"function","name":"namedOutputs","constant":true,"inputs":[],"outputs":[{"name":"str1","type":"string"},{"name":"str2","type":"string"}]},
{"type":"function","name":"collidingOutputs","constant":true,"inputs":[],"outputs":[{"name":"str","type":"string"},{"name":"Str","type":"string"}]},
{"type":"function","name":"anonOutputs","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"},{"name":"","type":"string"}]},
{"type":"function","name":"mixedOutputs","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"},{"name":"str","type":"string"}]}
]
@@ -140,12 +141,71 @@ var bindTests = []struct {
str1, err = b.NamedOutput(nil)
str1, err = b.AnonOutput(nil)
res, _ := b.NamedOutputs(nil)
str1, str2, err = b.CollidingOutputs(nil)
str1, str2, err = b.AnonOutputs(nil)
str1, str2, err = b.MixedOutputs(nil)
fmt.Println(str1, str2, res.Str1, res.Str2, err)
}`,
},
// Tests that named, anonymous and indexed events are handled correctly
{
`EventChecker`, ``, ``,
`
[
{"type":"event","name":"empty","inputs":[]},
{"type":"event","name":"indexed","inputs":[{"name":"addr","type":"address","indexed":true},{"name":"num","type":"int256","indexed":true}]},
{"type":"event","name":"mixed","inputs":[{"name":"addr","type":"address","indexed":true},{"name":"num","type":"int256"}]},
{"type":"event","name":"anonymous","anonymous":true,"inputs":[]},
{"type":"event","name":"dynamic","inputs":[{"name":"idxStr","type":"string","indexed":true},{"name":"idxDat","type":"bytes","indexed":true},{"name":"str","type":"string"},{"name":"dat","type":"bytes"}]}
]
`,
`if e, err := NewEventChecker(common.Address{}, nil); e == nil || err != nil {
t.Fatalf("binding (%v) nil or error (%v) not nil", e, nil)
} else if false { // Don't run, just compile and test types
var (
err error
res bool
str string
dat []byte
hash common.Hash
)
_, err = e.FilterEmpty(nil)
_, err = e.FilterIndexed(nil, []common.Address{}, []*big.Int{})
mit, err := e.FilterMixed(nil, []common.Address{})
res = mit.Next() // Make sure the iterator has a Next method
err = mit.Error() // Make sure the iterator has an Error method
err = mit.Close() // Make sure the iterator has a Close method
fmt.Println(mit.Event.Raw.BlockHash) // Make sure the raw log is contained within the results
fmt.Println(mit.Event.Num) // Make sure the unpacked non-indexed fields are present
fmt.Println(mit.Event.Addr) // Make sure the reconstructed indexed fields are present
dit, err := e.FilterDynamic(nil, []string{}, [][]byte{})
str = dit.Event.Str // Make sure non-indexed strings retain their type
dat = dit.Event.Dat // Make sure non-indexed bytes retain their type
hash = dit.Event.IdxStr // Make sure indexed strings turn into hashes
hash = dit.Event.IdxDat // Make sure indexed bytes turn into hashes
sink := make(chan *EventCheckerMixed)
sub, err := e.WatchMixed(nil, sink, []common.Address{})
defer sub.Unsubscribe()
event := <-sink
fmt.Println(event.Raw.BlockHash) // Make sure the raw log is contained within the results
fmt.Println(event.Num) // Make sure the unpacked non-indexed fields are present
fmt.Println(event.Addr) // Make sure the reconstructed indexed fields are present
fmt.Println(res, str, dat, hash, err)
}
// Run a tiny reflection test to ensure disallowed methods don't appear
if _, ok := reflect.TypeOf(&EventChecker{}).MethodByName("FilterAnonymous"); ok {
t.Errorf("binding has disallowed method (FilterAnonymous)")
}`,
},
// Test that contract interactions (deploy, transact and call) generate working code
{
`Interactor`,
@@ -169,7 +229,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy an interaction tester contract and call a transaction on it
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
@@ -210,7 +270,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a tuple tester contract and execute a structured call on it
_, _, getter, err := DeployGetter(auth, sim)
@@ -242,7 +302,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a tuple tester contract and execute a structured call on it
_, _, tupler, err := DeployTupler(auth, sim)
@@ -284,7 +344,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a slice tester contract and execute a n array call on it
_, _, slicer, err := DeploySlicer(auth, sim)
@@ -318,7 +378,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a default method invoker contract and execute its default method
_, _, defaulter, err := DeployDefaulter(auth, sim)
@@ -341,17 +401,17 @@ var bindTests = []struct {
{
`NonExistent`,
`
contract NonExistent {
function String() constant returns(string) {
return "I don't exist";
contract NonExistent {
function String() constant returns(string) {
return "I don't exist";
}
}
}
`,
`6060604052609f8060106000396000f3606060405260e060020a6000350463f97a60058114601a575b005b600060605260c0604052600d60809081527f4920646f6e27742065786973740000000000000000000000000000000000000060a052602060c0908152600d60e081905281906101009060a09080838184600060046012f15050815172ffffffffffffffffffffffffffffffffffffff1916909152505060405161012081900392509050f3`,
`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
`
// Create a simulator and wrap a non-deployed contract
sim := backends.NewSimulatedBackend()
sim := backends.NewSimulatedBackend(nil)
nonexistent, err := NewNonExistent(common.Address{}, sim)
if err != nil {
@@ -365,6 +425,384 @@ var bindTests = []struct {
}
`,
},
// Tests that gas estimation works for contracts with weird gas mechanics too.
{
`FunkyGasPattern`,
`
contract FunkyGasPattern {
string public field;
function SetField(string value) {
// This check will screw gas estimation! Good, good!
if (msg.gas < 100000) {
throw;
}
field = value;
}
}
`,
`606060405261021c806100126000396000f3606060405260e060020a600035046323fcf32a81146100265780634f28bf0e1461007b575b005b6040805160206004803580820135601f8101849004840285018401909552848452610024949193602493909291840191908190840183828082843750949650505050505050620186a05a101561014e57610002565b6100db60008054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281529291908301828280156102145780601f106101e957610100808354040283529160200191610214565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561013b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b505050565b8060006000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106101b557805160ff19168380011785555b506101499291505b808211156101e557600081556001016101a1565b82800160010185558215610199579182015b828111156101995782518260005055916020019190600101906101c7565b5090565b820191906000526020600020905b8154815290600101906020018083116101f757829003601f168201915b50505050508156`,
`[{"constant":false,"inputs":[{"name":"value","type":"string"}],"name":"SetField","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"field","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
`
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a funky gas pattern contract
_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
if err != nil {
t.Fatalf("Failed to deploy funky contract: %v", err)
}
sim.Commit()
// Set the field with automatic estimation and check that it succeeds
if _, err := limiter.SetField(auth, "automatic"); err != nil {
t.Fatalf("Failed to call automatically gased transaction: %v", err)
}
sim.Commit()
if field, _ := limiter.Field(nil); field != "automatic" {
t.Fatalf("Field mismatch: have %v, want %v", field, "automatic")
}
`,
},
// Test that constant functions can be called from an (optional) specified address
{
`CallFrom`,
`
contract CallFrom {
function callFrom() constant returns(address) {
return msg.sender;
}
}
`, `6060604052346000575b6086806100176000396000f300606060405263ffffffff60e060020a60003504166349f8e98281146022575b6000565b34600057602c6055565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b335b905600a165627a7a72305820aef6b7685c0fa24ba6027e4870404a57df701473fe4107741805c19f5138417c0029`,
`[{"constant":true,"inputs":[],"name":"callFrom","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}]`,
`
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a sender tester contract and execute a structured call on it
_, _, callfrom, err := DeployCallFrom(auth, sim)
if err != nil {
t.Fatalf("Failed to deploy sender contract: %v", err)
}
sim.Commit()
if res, err := callfrom.CallFrom(nil); err != nil {
t.Errorf("Failed to call constant function: %v", err)
} else if res != (common.Address{}) {
t.Errorf("Invalid address returned, want: %x, got: %x", (common.Address{}), res)
}
for _, addr := range []common.Address{common.Address{}, common.Address{1}, common.Address{2}} {
if res, err := callfrom.CallFrom(&bind.CallOpts{From: addr}); err != nil {
t.Fatalf("Failed to call constant function: %v", err)
} else if res != addr {
t.Fatalf("Invalid address returned, want: %x, got: %x", addr, res)
}
}
`,
},
{
`Underscorer`,
`
contract Underscorer {
function UnderscoredOutput() constant returns (int _int, string _string) {
return (314, "pi");
}
function LowerLowerCollision() constant returns (int _res, int res) {
return (1, 2);
}
function LowerUpperCollision() constant returns (int _res, int Res) {
return (1, 2);
}
function UpperLowerCollision() constant returns (int _Res, int res) {
return (1, 2);
}
function UpperUpperCollision() constant returns (int _Res, int Res) {
return (1, 2);
}
function PurelyUnderscoredOutput() constant returns (int _, int res) {
return (1, 2);
}
function AllPurelyUnderscoredOutput() constant returns (int _, int __) {
return (1, 2);
}
}
`, `6060604052341561000f57600080fd5b6103498061001e6000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461008857806367e6633d146100b85780639df484851461014d578063af7486ab1461017d578063b564b34d146101ad578063e02ab24d146101dd578063e409ca451461020d575b600080fd5b341561009357600080fd5b61009b61023d565b604051808381526020018281526020019250505060405180910390f35b34156100c357600080fd5b6100cb610252565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156101115780820151818401526020810190506100f6565b50505050905090810190601f16801561013e5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561015857600080fd5b6101606102a0565b604051808381526020018281526020019250505060405180910390f35b341561018857600080fd5b6101906102b5565b604051808381526020018281526020019250505060405180910390f35b34156101b857600080fd5b6101c06102ca565b604051808381526020018281526020019250505060405180910390f35b34156101e857600080fd5b6101f06102df565b604051808381526020018281526020019250505060405180910390f35b341561021857600080fd5b6102206102f4565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600061025c610309565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820c11dcfa136fc7d182ee4d34f0b12d988496228f7e2d02d2b5376d996ca1743d00029`,
`[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`,
`
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a underscorer tester contract and execute a structured call on it
_, _, underscorer, err := DeployUnderscorer(auth, sim)
if err != nil {
t.Fatalf("Failed to deploy underscorer contract: %v", err)
}
sim.Commit()
// Verify that underscored return values correctly parse into structs
if res, err := underscorer.UnderscoredOutput(nil); err != nil {
t.Errorf("Failed to call constant function: %v", err)
} else if res.Int.Cmp(big.NewInt(314)) != 0 || res.String != "pi" {
t.Errorf("Invalid result, want: {314, \"pi\"}, got: %+v", res)
}
// Verify that underscored and non-underscored name collisions force tuple outputs
var a, b *big.Int
a, b, _ = underscorer.LowerLowerCollision(nil)
a, b, _ = underscorer.LowerUpperCollision(nil)
a, b, _ = underscorer.UpperLowerCollision(nil)
a, b, _ = underscorer.UpperUpperCollision(nil)
a, b, _ = underscorer.PurelyUnderscoredOutput(nil)
a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil)
fmt.Println(a, b, err)
`,
},
// Tests that logs can be successfully filtered and decoded.
{
`Eventer`,
`
contract Eventer {
event SimpleEvent (
address indexed Addr,
bytes32 indexed Id,
bool indexed Flag,
uint Value
);
function raiseSimpleEvent(address addr, bytes32 id, bool flag, uint value) {
SimpleEvent(addr, id, flag, value);
}
event NodataEvent (
uint indexed Number,
int16 indexed Short,
uint32 indexed Long
);
function raiseNodataEvent(uint number, int16 short, uint32 long) {
NodataEvent(number, short, long);
}
event DynamicEvent (
string indexed IndexedString,
bytes indexed IndexedBytes,
string NonIndexedString,
bytes NonIndexedBytes
);
function raiseDynamicEvent(string str, bytes blob) {
DynamicEvent(str, blob, str, blob);
}
}
`,
`6060604052341561000f57600080fd5b61042c8061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063528300ff1461005c578063630c31e2146100fc578063c7d116dd14610156575b600080fd5b341561006757600080fd5b6100fa600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610194565b005b341561010757600080fd5b610154600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035600019169060200190919080351515906020019091908035906020019091905050610367565b005b341561016157600080fd5b610192600480803590602001909190803560010b90602001909190803563ffffffff169060200190919050506103c3565b005b806040518082805190602001908083835b6020831015156101ca57805182526020820191506020810190506020830392506101a5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020826040518082805190602001908083835b60208310151561022d5780518252602082019150602081019050602083039250610208565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f3281fd4f5e152dd3385df49104a3f633706e21c9e80672e88d3bcddf33101f008484604051808060200180602001838103835285818151815260200191508051906020019080838360005b838110156102c15780820151818401526020810190506102a6565b50505050905090810190601f1680156102ee5780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b8381101561032757808201518184015260208101905061030c565b50505050905090810190601f1680156103545780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a35050565b81151583600019168573ffffffffffffffffffffffffffffffffffffffff167f1f097de4289df643bd9c11011cc61367aa12983405c021056e706eb5ba1250c8846040518082815260200191505060405180910390a450505050565b8063ffffffff168260010b847f3ca7f3a77e5e6e15e781850bc82e32adfa378a2a609370db24b4d0fae10da2c960405160405180910390a45050505600a165627a7a72305820d1f8a8bbddbc5bb29f285891d6ae1eef8420c52afdc05e1573f6114d8e1714710029`,
`[{"constant":false,"inputs":[{"name":"str","type":"string"},{"name":"blob","type":"bytes"}],"name":"raiseDynamicEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"id","type":"bytes32"},{"name":"flag","type":"bool"},{"name":"value","type":"uint256"}],"name":"raiseSimpleEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"number","type":"uint256"},{"name":"short","type":"int16"},{"name":"long","type":"uint32"}],"name":"raiseNodataEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"Addr","type":"address"},{"indexed":true,"name":"Id","type":"bytes32"},{"indexed":true,"name":"Flag","type":"bool"},{"indexed":false,"name":"Value","type":"uint256"}],"name":"SimpleEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"Number","type":"uint256"},{"indexed":true,"name":"Short","type":"int16"},{"indexed":true,"name":"Long","type":"uint32"}],"name":"NodataEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"IndexedString","type":"string"},{"indexed":true,"name":"IndexedBytes","type":"bytes"},{"indexed":false,"name":"NonIndexedString","type":"string"},{"indexed":false,"name":"NonIndexedBytes","type":"bytes"}],"name":"DynamicEvent","type":"event"}]`,
`
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy an eventer contract
_, _, eventer, err := DeployEventer(auth, sim)
if err != nil {
t.Fatalf("Failed to deploy eventer contract: %v", err)
}
sim.Commit()
// Inject a few events into the contract, gradually more in each block
for i := 1; i <= 3; i++ {
for j := 1; j <= i; j++ {
if _, err := eventer.RaiseSimpleEvent(auth, common.Address{byte(j)}, [32]byte{byte(j)}, true, big.NewInt(int64(10*i+j))); err != nil {
t.Fatalf("block %d, event %d: raise failed: %v", i, j, err)
}
}
sim.Commit()
}
// Test filtering for certain events and ensure they can be found
sit, err := eventer.FilterSimpleEvent(nil, []common.Address{common.Address{1}, common.Address{3}}, [][32]byte{{byte(1)}, {byte(2)}, {byte(3)}}, []bool{true})
if err != nil {
t.Fatalf("failed to filter for simple events: %v", err)
}
defer sit.Close()
sit.Next()
if sit.Event.Value.Uint64() != 11 || !sit.Event.Flag {
t.Errorf("simple log content mismatch: have %v, want {11, true}", sit.Event)
}
sit.Next()
if sit.Event.Value.Uint64() != 21 || !sit.Event.Flag {
t.Errorf("simple log content mismatch: have %v, want {21, true}", sit.Event)
}
sit.Next()
if sit.Event.Value.Uint64() != 31 || !sit.Event.Flag {
t.Errorf("simple log content mismatch: have %v, want {31, true}", sit.Event)
}
sit.Next()
if sit.Event.Value.Uint64() != 33 || !sit.Event.Flag {
t.Errorf("simple log content mismatch: have %v, want {33, true}", sit.Event)
}
if sit.Next() {
t.Errorf("unexpected simple event found: %+v", sit.Event)
}
if err = sit.Error(); err != nil {
t.Fatalf("simple event iteration failed: %v", err)
}
// Test raising and filtering for an event with no data component
if _, err := eventer.RaiseNodataEvent(auth, big.NewInt(314), 141, 271); err != nil {
t.Fatalf("failed to raise nodata event: %v", err)
}
sim.Commit()
nit, err := eventer.FilterNodataEvent(nil, []*big.Int{big.NewInt(314)}, []int16{140, 141, 142}, []uint32{271})
if err != nil {
t.Fatalf("failed to filter for nodata events: %v", err)
}
defer nit.Close()
if !nit.Next() {
t.Fatalf("nodata log not found: %v", nit.Error())
}
if nit.Event.Number.Uint64() != 314 {
t.Errorf("nodata log content mismatch: have %v, want 314", nit.Event.Number)
}
if nit.Next() {
t.Errorf("unexpected nodata event found: %+v", nit.Event)
}
if err = nit.Error(); err != nil {
t.Fatalf("nodata event iteration failed: %v", err)
}
// Test raising and filtering for events with dynamic indexed components
if _, err := eventer.RaiseDynamicEvent(auth, "Hello", []byte("World")); err != nil {
t.Fatalf("failed to raise dynamic event: %v", err)
}
sim.Commit()
dit, err := eventer.FilterDynamicEvent(nil, []string{"Hi", "Hello", "Bye"}, [][]byte{[]byte("World")})
if err != nil {
t.Fatalf("failed to filter for dynamic events: %v", err)
}
defer dit.Close()
if !dit.Next() {
t.Fatalf("dynamic log not found: %v", dit.Error())
}
if dit.Event.NonIndexedString != "Hello" || string(dit.Event.NonIndexedBytes) != "World" || dit.Event.IndexedString != common.HexToHash("0x06b3dfaec148fb1bb2b066f10ec285e7c9bf402ab32aa78a5d38e34566810cd2") || dit.Event.IndexedBytes != common.HexToHash("0xf2208c967df089f60420785795c0a9ba8896b0f6f1867fa7f1f12ad6f79c1a18") {
t.Errorf("dynamic log content mismatch: have %v, want {'0x06b3dfaec148fb1bb2b066f10ec285e7c9bf402ab32aa78a5d38e34566810cd2, '0xf2208c967df089f60420785795c0a9ba8896b0f6f1867fa7f1f12ad6f79c1a18', 'Hello', 'World'}", dit.Event)
}
if dit.Next() {
t.Errorf("unexpected dynamic event found: %+v", dit.Event)
}
if err = dit.Error(); err != nil {
t.Fatalf("dynamic event iteration failed: %v", err)
}
// Test subscribing to an event and raising it afterwards
ch := make(chan *EventerSimpleEvent, 16)
sub, err := eventer.WatchSimpleEvent(nil, ch, nil, nil, nil)
if err != nil {
t.Fatalf("failed to subscribe to simple events: %v", err)
}
if _, err := eventer.RaiseSimpleEvent(auth, common.Address{255}, [32]byte{255}, true, big.NewInt(255)); err != nil {
t.Fatalf("failed to raise subscribed simple event: %v", err)
}
sim.Commit()
select {
case event := <-ch:
if event.Value.Uint64() != 255 {
t.Errorf("simple log content mismatch: have %v, want 255", event)
}
case <-time.After(250 * time.Millisecond):
t.Fatalf("subscribed simple event didn't arrive")
}
// Unsubscribe from the event and make sure we're not delivered more
sub.Unsubscribe()
if _, err := eventer.RaiseSimpleEvent(auth, common.Address{254}, [32]byte{254}, true, big.NewInt(254)); err != nil {
t.Fatalf("failed to raise subscribed simple event: %v", err)
}
sim.Commit()
select {
case event := <-ch:
t.Fatalf("unsubscribed simple event arrived: %v", event)
case <-time.After(250 * time.Millisecond):
}
`,
},
{
`DeeplyNestedArray`,
`
contract DeeplyNestedArray {
uint64[3][4][5] public deepUint64Array;
function storeDeepUintArray(uint64[3][4][5] arr) public {
deepUint64Array = arr;
}
function retrieveDeepArray() public view returns (uint64[3][4][5]) {
return deepUint64Array;
}
}
`,
`6060604052341561000f57600080fd5b6106438061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063344248551461005c5780638ed4573a1461011457806398ed1856146101ab575b600080fd5b341561006757600080fd5b610112600480806107800190600580602002604051908101604052809291906000905b828210156101055783826101800201600480602002604051908101604052809291906000905b828210156100f25783826060020160038060200260405190810160405280929190826003602002808284378201915050505050815260200190600101906100b0565b505050508152602001906001019061008a565b5050505091905050610208565b005b341561011f57600080fd5b61012761021d565b604051808260056000925b8184101561019b578284602002015160046000925b8184101561018d5782846020020151600360200280838360005b8381101561017c578082015181840152602081019050610161565b505050509050019260010192610147565b925050509260010192610132565b9250505091505060405180910390f35b34156101b657600080fd5b6101de6004808035906020019091908035906020019091908035906020019091905050610309565b604051808267ffffffffffffffff1667ffffffffffffffff16815260200191505060405180910390f35b80600090600561021992919061035f565b5050565b6102256103b0565b6000600580602002604051908101604052809291906000905b8282101561030057838260040201600480602002604051908101604052809291906000905b828210156102ed578382016003806020026040519081016040528092919082600380156102d9576020028201916000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff16815260200190600801906020826007010492830192600103820291508084116102945790505b505050505081526020019060010190610263565b505050508152602001906001019061023e565b50505050905090565b60008360058110151561031857fe5b600402018260048110151561032957fe5b018160038110151561033757fe5b6004918282040191900660080292509250509054906101000a900467ffffffffffffffff1681565b826005600402810192821561039f579160200282015b8281111561039e5782518290600461038e9291906103df565b5091602001919060040190610375565b5b5090506103ac919061042d565b5090565b610780604051908101604052806005905b6103c9610459565b8152602001906001900390816103c15790505090565b826004810192821561041c579160200282015b8281111561041b5782518290600361040b929190610488565b50916020019190600101906103f2565b5b5090506104299190610536565b5090565b61045691905b8082111561045257600081816104499190610562565b50600401610433565b5090565b90565b610180604051908101604052806004905b6104726105a7565b81526020019060019003908161046a5790505090565b82600380016004900481019282156105255791602002820160005b838211156104ef57835183826101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555092602001926008016020816007010492830192600103026104a3565b80156105235782816101000a81549067ffffffffffffffff02191690556008016020816007010492830192600103026104ef565b505b50905061053291906105d9565b5090565b61055f91905b8082111561055b57600081816105529190610610565b5060010161053c565b5090565b90565b50600081816105719190610610565b50600101600081816105839190610610565b50600101600081816105959190610610565b5060010160006105a59190610610565b565b6060604051908101604052806003905b600067ffffffffffffffff168152602001906001900390816105b75790505090565b61060d91905b8082111561060957600081816101000a81549067ffffffffffffffff0219169055506001016105df565b5090565b90565b50600090555600a165627a7a7230582087e5a43f6965ab6ef7a4ff056ab80ed78fd8c15cff57715a1bf34ec76a93661c0029`,
`[{"constant":false,"inputs":[{"name":"arr","type":"uint64[3][4][5]"}],"name":"storeDeepUintArray","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"retrieveDeepArray","outputs":[{"name":"","type":"uint64[3][4][5]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"name":"deepUint64Array","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"}]`,
`
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
//deploy the test contract
_, _, testContract, err := DeployDeeplyNestedArray(auth, sim)
if err != nil {
t.Fatalf("Failed to deploy test contract: %v", err)
}
// Finish deploy.
sim.Commit()
//Create coordinate-filled array, for testing purposes.
testArr := [5][4][3]uint64{}
for i := 0; i < 5; i++ {
testArr[i] = [4][3]uint64{}
for j := 0; j < 4; j++ {
testArr[i][j] = [3]uint64{}
for k := 0; k < 3; k++ {
//pack the coordinates, each array value will be unique, and can be validated easily.
testArr[i][j][k] = uint64(i) << 16 | uint64(j) << 8 | uint64(k)
}
}
}
if _, err := testContract.StoreDeepUintArray(&bind.TransactOpts{
From: auth.From,
Signer: auth.Signer,
}, testArr); err != nil {
t.Fatalf("Failed to store nested array in test contract: %v", err)
}
sim.Commit()
retrievedArr, err := testContract.RetrieveDeepArray(&bind.CallOpts{
From: auth.From,
Pending: false,
})
if err != nil {
t.Fatalf("Failed to retrieve nested array from test contract: %v", err)
}
//quick check to see if contents were copied
// (See accounts/abi/unpack_test.go for more extensive testing)
if retrievedArr[4][3][2] != testArr[4][3][2] {
t.Fatalf("Retrieved value does not match expected value! got: %d, expected: %d. %v", retrievedArr[4][3][2], testArr[4][3][2], err)
}`,
},
}
// Tests that packages generated by the binder can be successfully compiled and
@@ -376,8 +814,8 @@ func TestBindings(t *testing.T) {
t.Skip("go sdk not found for testing")
}
// Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845)
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend())\n}")
linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil)
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}")
linkTestDeps, err := imports.Process(os.TempDir(), []byte(linkTestCode), nil)
if err != nil {
t.Fatalf("failed check for goimports symlink bug: %v", err)
}
@@ -416,7 +854,7 @@ func TestBindings(t *testing.T) {
}
}
// Test the entire package and report any failures
cmd := exec.Command(gocmd, "test", "-v")
cmd := exec.Command(gocmd, "test", "-v", "-count", "1")
cmd.Dir = pkg
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("failed to run binding test: %v\n%s", err, out)

View File

@@ -32,6 +32,7 @@ type tmplContract struct {
Constructor abi.Method // Contract constructor for deploy parametrization
Calls map[string]*tmplMethod // Contract calls that only read state data
Transacts map[string]*tmplMethod // Contract calls that write state data
Events map[string]*tmplEvent // Contract events accessors
}
// tmplMethod is a wrapper around an abi.Method that contains a few preprocessed
@@ -39,7 +40,13 @@ type tmplContract struct {
type tmplMethod struct {
Original abi.Method // Original method as parsed by the abi package
Normalized abi.Method // Normalized version of the parsed method (capitalized names, non-anonymous args/returns)
Structured bool // Whether the returns should be accumulated into a contract
Structured bool // Whether the returns should be accumulated into a struct
}
// tmplEvent is a wrapper around an a
type tmplEvent struct {
Original abi.Event // Original event as parsed by the abi package
Normalized abi.Event // Normalized version of the parsed fields
}
// tmplSource is language to template mapping containing all the supported
@@ -52,8 +59,8 @@ var tmplSource = map[Lang]string{
// tmplSourceGo is the Go source template use to generate the contract binding
// based on.
const tmplSourceGo = `
// This file is an automatically generated Go binding. Do not modify as any
// change will likely be lost upon the next re-generation!
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package {{.Package}}
@@ -75,7 +82,7 @@ package {{.Package}}
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract} }, nil
return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
}
{{end}}
@@ -83,6 +90,7 @@ package {{.Package}}
type {{.Type}} struct {
{{.Type}}Caller // Read-only binding to the contract
{{.Type}}Transactor // Write-only binding to the contract
{{.Type}}Filterer // Log filterer for contract events
}
// {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract.
@@ -95,6 +103,11 @@ package {{.Package}}
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events.
type {{.Type}}Filterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// {{.Type}}Session is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type {{.Type}}Session struct {
@@ -134,16 +147,16 @@ package {{.Package}}
// New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract.
func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) {
contract, err := bind{{.Type}}(address, backend, backend)
contract, err := bind{{.Type}}(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract} }, nil
return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
}
// New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract.
func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) {
contract, err := bind{{.Type}}(address, caller, nil)
contract, err := bind{{.Type}}(address, caller, nil, nil)
if err != nil {
return nil, err
}
@@ -152,20 +165,29 @@ package {{.Package}}
// New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract.
func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) {
contract, err := bind{{.Type}}(address, nil, transactor)
contract, err := bind{{.Type}}(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &{{.Type}}Transactor{contract: contract}, nil
}
// New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract.
func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) {
contract, err := bind{{.Type}}(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &{{.Type}}Filterer{contract: contract}, nil
}
// bind{{.Type}} binds a generic wrapper to an already deployed contract.
func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader({{.Type}}ABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor), nil
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
@@ -263,6 +285,137 @@ package {{.Package}}
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
}
{{end}}
{{range .Events}}
// {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract.
type {{$contract.Type}}{{.Normalized.Name}}Iterator struct {
Event *{{$contract.Type}}{{.Normalized.Name}} // Event containing the contract specifics and raw log
contract *bind.BoundContract // Generic contract to use for unpacking event data
event string // Event name to use for unpacking event data
logs chan types.Log // Log channel receiving the found contract events
sub ethereum.Subscription // Subscription for errors, completion and termination
done bool // Whether the subscription completed delivering logs
fail error // Occurred error to stop iteration
}
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Next() bool {
// If the iterator failed, stop iterating
if (it.fail != nil) {
return false
}
// If the iterator completed, deliver directly whatever's available
if (it.done) {
select {
case log := <-it.logs:
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
default:
return false
}
}
// Iterator still in progress, wait for either a data or an error event
select {
case log := <-it.logs:
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
it.fail = err
return false
}
it.Event.Raw = log
return true
case err := <-it.sub.Err():
it.done = true
it.fail = err
return it.Next()
}
}
// Error returns any retrieval or parsing error occurred during filtering.
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error {
return it.fail
}
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error {
it.sub.Unsubscribe()
return nil
}
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract.
type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}}
{{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type}}{{else}}{{bindtype .Type}}{{end}}; {{end}}
Raw types.Log // Blockchain specific contextual infos
}
// Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.Id}}.
//
// Solidity: {{.Original.String}}
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) {
{{range .Normalized.Inputs}}
{{if .Indexed}}var {{.Name}}Rule []interface{}
for _, {{.Name}}Item := range {{.Name}} {
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
}{{end}}{{end}}
logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
if err != nil {
return nil, err
}
return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil
}
// Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.Id}}.
//
// Solidity: {{.Original.String}}
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type}}{{end}}{{end}}) (event.Subscription, error) {
{{range .Normalized.Inputs}}
{{if .Indexed}}var {{.Name}}Rule []interface{}
for _, {{.Name}}Item := range {{.Name}} {
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
}{{end}}{{end}}
logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
if err != nil {
return nil, err
}
return event.NewSubscription(func(quit <-chan struct{}) error {
defer sub.Unsubscribe()
for {
select {
case log := <-logs:
// New log arrived, parse the event and forward to the user
event := new({{$contract.Type}}{{.Normalized.Name}})
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
return err
}
event.Raw = log
select {
case sink <- event:
case err := <-sub.Err():
return err
case <-quit:
return nil
}
case err := <-sub.Err():
return err
case <-quit:
return nil
}
}
}), nil
}
{{end}}
{{end}}
`

189
accounts/abi/bind/topics.go Normal file
View File

@@ -0,0 +1,189 @@
// Copyright 2018 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 bind
import (
"errors"
"fmt"
"math/big"
"reflect"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
// makeTopics converts a filter query argument list into a filter topic set.
func makeTopics(query ...[]interface{}) ([][]common.Hash, error) {
topics := make([][]common.Hash, len(query))
for i, filter := range query {
for _, rule := range filter {
var topic common.Hash
// Try to generate the topic based on simple types
switch rule := rule.(type) {
case common.Hash:
copy(topic[:], rule[:])
case common.Address:
copy(topic[common.HashLength-common.AddressLength:], rule[:])
case *big.Int:
blob := rule.Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case bool:
if rule {
topic[common.HashLength-1] = 1
}
case int8:
blob := big.NewInt(int64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case int16:
blob := big.NewInt(int64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case int32:
blob := big.NewInt(int64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case int64:
blob := big.NewInt(rule).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case uint8:
blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case uint16:
blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case uint32:
blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case uint64:
blob := new(big.Int).SetUint64(rule).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case string:
hash := crypto.Keccak256Hash([]byte(rule))
copy(topic[:], hash[:])
case []byte:
hash := crypto.Keccak256Hash(rule)
copy(topic[:], hash[:])
default:
// Attempt to generate the topic from funky types
val := reflect.ValueOf(rule)
switch {
case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8:
reflect.Copy(reflect.ValueOf(topic[common.HashLength-val.Len():]), val)
default:
return nil, fmt.Errorf("unsupported indexed type: %T", rule)
}
}
topics[i] = append(topics[i], topic)
}
}
return topics, nil
}
// Big batch of reflect types for topic reconstruction.
var (
reflectHash = reflect.TypeOf(common.Hash{})
reflectAddress = reflect.TypeOf(common.Address{})
reflectBigInt = reflect.TypeOf(new(big.Int))
)
// parseTopics converts the indexed topic fields into actual log field values.
//
// Note, dynamic types cannot be reconstructed since they get mapped to Keccak256
// hashes as the topic value!
func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) error {
// Sanity check that the fields and topics match up
if len(fields) != len(topics) {
return errors.New("topic/field count mismatch")
}
// Iterate over all the fields and reconstruct them from topics
for _, arg := range fields {
if !arg.Indexed {
return errors.New("non-indexed field in topic reconstruction")
}
field := reflect.ValueOf(out).Elem().FieldByName(capitalise(arg.Name))
// Try to parse the topic back into the fields based on primitive types
switch field.Kind() {
case reflect.Bool:
if topics[0][common.HashLength-1] == 1 {
field.Set(reflect.ValueOf(true))
}
case reflect.Int8:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(int8(num.Int64())))
case reflect.Int16:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(int16(num.Int64())))
case reflect.Int32:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(int32(num.Int64())))
case reflect.Int64:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(num.Int64()))
case reflect.Uint8:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(uint8(num.Uint64())))
case reflect.Uint16:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(uint16(num.Uint64())))
case reflect.Uint32:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(uint32(num.Uint64())))
case reflect.Uint64:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(num.Uint64()))
default:
// Ran out of plain primitive types, try custom types
switch field.Type() {
case reflectHash: // Also covers all dynamic types
field.Set(reflect.ValueOf(topics[0]))
case reflectAddress:
var addr common.Address
copy(addr[:], topics[0][common.HashLength-common.AddressLength:])
field.Set(reflect.ValueOf(addr))
case reflectBigInt:
num := new(big.Int).SetBytes(topics[0][:])
field.Set(reflect.ValueOf(num))
default:
// Ran out of custom types, try the crazies
switch {
case arg.Type.T == abi.FixedBytesTy:
reflect.Copy(field, reflect.ValueOf(topics[0][common.HashLength-arg.Type.Size:]))
default:
return fmt.Errorf("unsupported indexed type: %v", arg.Type)
}
}
}
topics = topics[1:]
}
return nil
}

View File

@@ -17,31 +17,31 @@
package bind
import (
"context"
"fmt"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"golang.org/x/net/context"
"github.com/ethereum/go-ethereum/log"
)
// WaitMined waits for tx to be mined on the blockchain.
// It stops waiting when the context is canceled.
func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*types.Receipt, error) {
queryTicker := time.NewTicker(1 * time.Second)
queryTicker := time.NewTicker(time.Second)
defer queryTicker.Stop()
loghash := tx.Hash().Hex()[:8]
logger := log.New("hash", tx.Hash())
for {
receipt, err := b.TransactionReceipt(ctx, tx.Hash())
if receipt != nil {
return receipt, nil
}
if err != nil {
glog.V(logger.Detail).Infof("tx %x error: %v", loghash, err)
logger.Trace("Receipt retrieval failed", "err", err)
} else {
glog.V(logger.Detail).Infof("tx %x not yet mined...", loghash)
logger.Trace("Transaction not yet mined")
}
// Wait for the next round.
select {

View File

@@ -17,6 +17,7 @@
package bind_test
import (
"context"
"math/big"
"testing"
"time"
@@ -27,25 +28,24 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"golang.org/x/net/context"
)
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
var waitDeployedTests = map[string]struct {
code string
gas *big.Int
gas uint64
wantAddress common.Address
wantErr error
}{
"successful deploy": {
code: `6060604052600a8060106000396000f360606040526008565b00`,
gas: big.NewInt(3000000),
gas: 3000000,
wantAddress: common.HexToAddress("0x3a220f351252089d385b29beca14e27f204c296a"),
},
"empty code": {
code: ``,
gas: big.NewInt(300000),
gas: 300000,
wantErr: bind.ErrNoCodeAfterDeploy,
wantAddress: common.HexToAddress("0x3a220f351252089d385b29beca14e27f204c296a"),
},
@@ -53,14 +53,13 @@ var waitDeployedTests = map[string]struct {
func TestWaitDeployed(t *testing.T) {
for name, test := range waitDeployedTests {
backend := backends.NewSimulatedBackend(core.GenesisAccount{
Address: crypto.PubkeyToAddress(testKey.PublicKey),
Balance: big.NewInt(10000000000),
backend := backends.NewSimulatedBackend(core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)},
})
// Create the transaction.
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, testKey)
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
// Wait for it to get mined in the background.
var (

View File

@@ -17,10 +17,15 @@
package abi
import (
"errors"
"fmt"
"reflect"
)
var (
errBadBool = errors.New("abi: improperly encoded boolean value")
)
// formatSliceString formats the reflection kind with the given slice size
// and returns a formatted string representation.
func formatSliceString(kind reflect.Kind, sliceSize int) string {
@@ -34,22 +39,23 @@ func formatSliceString(kind reflect.Kind, sliceSize int) string {
// type in t.
func sliceTypeCheck(t Type, val reflect.Value) error {
if val.Kind() != reflect.Slice && val.Kind() != reflect.Array {
return typeErr(formatSliceString(t.Kind, t.SliceSize), val.Type())
}
if t.IsArray && val.Len() != t.SliceSize {
return typeErr(formatSliceString(t.Elem.Kind, t.SliceSize), formatSliceString(val.Type().Elem().Kind(), val.Len()))
return typeErr(formatSliceString(t.Kind, t.Size), val.Type())
}
if t.Elem.IsSlice {
if t.T == ArrayTy && val.Len() != t.Size {
return typeErr(formatSliceString(t.Elem.Kind, t.Size), formatSliceString(val.Type().Elem().Kind(), val.Len()))
}
if t.Elem.T == SliceTy {
if val.Len() > 0 {
return sliceTypeCheck(*t.Elem, val.Index(0))
}
} else if t.Elem.IsArray {
} else if t.Elem.T == ArrayTy {
return sliceTypeCheck(*t.Elem, val.Index(0))
}
if elemKind := val.Type().Elem().Kind(); elemKind != t.Elem.Kind {
return typeErr(formatSliceString(t.Elem.Kind, t.SliceSize), val.Type())
return typeErr(formatSliceString(t.Elem.Kind, t.Size), val.Type())
}
return nil
}
@@ -57,20 +63,19 @@ func sliceTypeCheck(t Type, val reflect.Value) error {
// typeCheck checks that the given reflection value can be assigned to the reflection
// type in t.
func typeCheck(t Type, value reflect.Value) error {
if t.IsSlice || t.IsArray {
if t.T == SliceTy || t.T == ArrayTy {
return sliceTypeCheck(t, value)
}
// Check base type validity. Element types will be checked later on.
if t.Kind != value.Kind() {
return typeErr(t.Kind, value.Kind())
} else if t.T == FixedBytesTy && t.Size != value.Len() {
return typeErr(t.Type, value.Type())
} else {
return nil
}
return nil
}
// varErr returns a formatted error.
func varErr(expected, got reflect.Kind) error {
return typeErr(expected, got)
}
// typeErr returns a formatted type casting error.

View File

@@ -25,10 +25,23 @@ import (
)
// Event is an event potentially triggered by the EVM's LOG mechanism. The Event
// holds type information (inputs) about the yielded output
// holds type information (inputs) about the yielded output. Anonymous events
// don't get the signature canonical representation as the first LOG topic.
type Event struct {
Name string
Inputs []Argument
Name string
Anonymous bool
Inputs Arguments
}
func (event Event) String() string {
inputs := make([]string, len(event.Inputs))
for i, input := range event.Inputs {
inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type)
if input.Indexed {
inputs[i] = fmt.Sprintf("%v indexed %v", input.Name, input.Type)
}
}
return fmt.Sprintf("event %v(%v)", event.Name, strings.Join(inputs, ", "))
}
// Id returns the canonical representation of the event's signature used by the

View File

@@ -17,13 +17,53 @@
package abi
import (
"bytes"
"encoding/hex"
"encoding/json"
"math/big"
"reflect"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var jsonEventTransfer = []byte(`{
"anonymous": false,
"inputs": [
{
"indexed": true, "name": "from", "type": "address"
}, {
"indexed": true, "name": "to", "type": "address"
}, {
"indexed": false, "name": "value", "type": "uint256"
}],
"name": "Transfer",
"type": "event"
}`)
var jsonEventPledge = []byte(`{
"anonymous": false,
"inputs": [{
"indexed": false, "name": "who", "type": "address"
}, {
"indexed": false, "name": "wad", "type": "uint128"
}, {
"indexed": false, "name": "currency", "type": "bytes3"
}],
"name": "Pledge",
"type": "event"
}`)
// 1000000
var transferData1 = "00000000000000000000000000000000000000000000000000000000000f4240"
// "0x00Ce0d46d924CC8437c806721496599FC3FFA268", 2218516807680, "usd"
var pledgeData1 = "00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa2680000000000000000000000000000000000000000000000000000020489e800007573640000000000000000000000000000000000000000000000000000000000"
func TestEventId(t *testing.T) {
var table = []struct {
definition string
@@ -31,7 +71,7 @@ func TestEventId(t *testing.T) {
}{
{
definition: `[
{ "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint" }] },
{ "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint256" }] },
{ "type" : "event", "name" : "check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] }
]`,
expectations: map[string]common.Hash{
@@ -54,3 +94,223 @@ func TestEventId(t *testing.T) {
}
}
}
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
func TestEventMultiValueWithArrayUnpack(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
type testStruct struct {
Value1 [2]uint8
Value2 uint8
}
abi, err := JSON(strings.NewReader(definition))
require.NoError(t, err)
var b bytes.Buffer
var i uint8 = 1
for ; i <= 3; i++ {
b.Write(packNum(reflect.ValueOf(i)))
}
var rst testStruct
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes()))
require.Equal(t, [2]uint8{1, 2}, rst.Value1)
require.Equal(t, uint8(3), rst.Value2)
}
func TestEventTupleUnpack(t *testing.T) {
type EventTransfer struct {
Value *big.Int
}
type EventPledge struct {
Who common.Address
Wad *big.Int
Currency [3]byte
}
type BadEventPledge struct {
Who string
Wad int
Currency [3]byte
}
bigint := new(big.Int)
bigintExpected := big.NewInt(1000000)
bigintExpected2 := big.NewInt(2218516807680)
addr := common.HexToAddress("0x00Ce0d46d924CC8437c806721496599FC3FFA268")
var testCases = []struct {
data string
dest interface{}
expected interface{}
jsonLog []byte
error string
name string
}{{
transferData1,
&EventTransfer{},
&EventTransfer{Value: bigintExpected},
jsonEventTransfer,
"",
"Can unpack ERC20 Transfer event into structure",
}, {
transferData1,
&[]interface{}{&bigint},
&[]interface{}{&bigintExpected},
jsonEventTransfer,
"",
"Can unpack ERC20 Transfer event into slice",
}, {
pledgeData1,
&EventPledge{},
&EventPledge{
addr,
bigintExpected2,
[3]byte{'u', 's', 'd'}},
jsonEventPledge,
"",
"Can unpack Pledge event into structure",
}, {
pledgeData1,
&[]interface{}{&common.Address{}, &bigint, &[3]byte{}},
&[]interface{}{
&addr,
&bigintExpected2,
&[3]byte{'u', 's', 'd'}},
jsonEventPledge,
"",
"Can unpack Pledge event into slice",
}, {
pledgeData1,
&[3]interface{}{&common.Address{}, &bigint, &[3]byte{}},
&[3]interface{}{
&addr,
&bigintExpected2,
&[3]byte{'u', 's', 'd'}},
jsonEventPledge,
"",
"Can unpack Pledge event into an array",
}, {
pledgeData1,
&[]interface{}{new(int), 0, 0},
&[]interface{}{},
jsonEventPledge,
"abi: cannot unmarshal common.Address in to int",
"Can not unpack Pledge event into slice with wrong types",
}, {
pledgeData1,
&BadEventPledge{},
&BadEventPledge{},
jsonEventPledge,
"abi: cannot unmarshal common.Address in to string",
"Can not unpack Pledge event into struct with wrong filed types",
}, {
pledgeData1,
&[]interface{}{common.Address{}, new(big.Int)},
&[]interface{}{},
jsonEventPledge,
"abi: insufficient number of elements in the list/array for unpack, want 3, got 2",
"Can not unpack Pledge event into too short slice",
}, {
pledgeData1,
new(map[string]interface{}),
&[]interface{}{},
jsonEventPledge,
"abi: cannot unmarshal tuple into map[string]interface {}",
"Can not unpack Pledge event into map",
}}
for _, tc := range testCases {
assert := assert.New(t)
tc := tc
t.Run(tc.name, func(t *testing.T) {
err := unpackTestEventData(tc.dest, tc.data, tc.jsonLog, assert)
if tc.error == "" {
assert.Nil(err, "Should be able to unpack event data.")
assert.Equal(tc.expected, tc.dest, tc.name)
} else {
assert.EqualError(err, tc.error)
}
})
}
}
func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, assert *assert.Assertions) error {
data, err := hex.DecodeString(hexData)
assert.NoError(err, "Hex data should be a correct hex-string")
var e Event
assert.NoError(json.Unmarshal(jsonEvent, &e), "Should be able to unmarshal event ABI")
a := ABI{Events: map[string]Event{"e": e}}
return a.Unpack(dest, "e", data)
}
/*
Taken from
https://github.com/ethereum/go-ethereum/pull/15568
*/
type testResult struct {
Values [2]*big.Int
Value1 *big.Int
Value2 *big.Int
}
type testCase struct {
definition string
want testResult
}
func (tc testCase) encoded(intType, arrayType Type) []byte {
var b bytes.Buffer
if tc.want.Value1 != nil {
val, _ := intType.pack(reflect.ValueOf(tc.want.Value1))
b.Write(val)
}
if !reflect.DeepEqual(tc.want.Values, [2]*big.Int{nil, nil}) {
val, _ := arrayType.pack(reflect.ValueOf(tc.want.Values))
b.Write(val)
}
if tc.want.Value2 != nil {
val, _ := intType.pack(reflect.ValueOf(tc.want.Value2))
b.Write(val)
}
return b.Bytes()
}
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
func TestEventUnpackIndexed(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
type testStruct struct {
Value1 uint8
Value2 uint8
}
abi, err := JSON(strings.NewReader(definition))
require.NoError(t, err)
var b bytes.Buffer
b.Write(packNum(reflect.ValueOf(uint8(8))))
var rst testStruct
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes()))
require.Equal(t, uint8(0), rst.Value1)
require.Equal(t, uint8(8), rst.Value2)
}
// TestEventIndexedWithArrayUnpack verifies that decoder will not overlow when static array is indexed input.
func TestEventIndexedWithArrayUnpack(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]`
type testStruct struct {
Value1 [2]uint8
Value2 string
}
abi, err := JSON(strings.NewReader(definition))
require.NoError(t, err)
var b bytes.Buffer
stringOut := "abc"
// number of fields that will be encoded * 32
b.Write(packNum(reflect.ValueOf(32)))
b.Write(packNum(reflect.ValueOf(len(stringOut))))
b.Write(common.RightPadBytes([]byte(stringOut), 32))
var rst testStruct
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes()))
require.Equal(t, [2]uint8{0, 0}, rst.Value1)
require.Equal(t, stringOut, rst.Value2)
}

View File

@@ -18,13 +18,12 @@ package abi
import (
"fmt"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/crypto"
)
// Callable method given a `Name` and whether the method is a constant.
// Method represents a callable given a `Name` and whether the method is a constant.
// If the method is `Const` no transaction needs to be created for this
// particular Method call. It can easily be simulated using a local VM.
// For example a `Balance()` method only needs to retrieve something
@@ -35,46 +34,8 @@ import (
type Method struct {
Name string
Const bool
Inputs []Argument
Outputs []Argument
}
func (m Method) pack(method Method, args ...interface{}) ([]byte, error) {
// Make sure arguments match up and pack them
if len(args) != len(method.Inputs) {
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs))
}
// variable input is the output appended at the end of packed
// output. This is used for strings and bytes types input.
var variableInput []byte
var ret []byte
for i, a := range args {
input := method.Inputs[i]
// pack the input
packed, err := input.Type.pack(reflect.ValueOf(a))
if err != nil {
return nil, fmt.Errorf("`%s` %v", method.Name, err)
}
// check for a slice type (string, bytes, slice)
if input.Type.requiresLengthPrefix() {
// calculate the offset
offset := len(method.Inputs)*32 + len(variableInput)
// set the offset
ret = append(ret, packNum(reflect.ValueOf(offset))...)
// Append the packed output to the variable input. The variable input
// will be appended at the end of the input.
variableInput = append(variableInput, packed...)
} else {
// append the packed value to the input
ret = append(ret, packed...)
}
}
// append the variable input at the end of the packed input
ret = append(ret, variableInput...)
return ret, nil
Inputs Arguments
Outputs Arguments
}
// Sig returns the methods string signature according to the ABI spec.
@@ -84,35 +45,35 @@ func (m Method) pack(method Method, args ...interface{}) ([]byte, error) {
// function foo(uint32 a, int b) = "foo(uint32,int256)"
//
// Please note that "int" is substitute for its canonical representation "int256"
func (m Method) Sig() string {
types := make([]string, len(m.Inputs))
func (method Method) Sig() string {
types := make([]string, len(method.Inputs))
i := 0
for _, input := range m.Inputs {
for _, input := range method.Inputs {
types[i] = input.Type.String()
i++
}
return fmt.Sprintf("%v(%v)", m.Name, strings.Join(types, ","))
return fmt.Sprintf("%v(%v)", method.Name, strings.Join(types, ","))
}
func (m Method) String() string {
inputs := make([]string, len(m.Inputs))
for i, input := range m.Inputs {
func (method Method) String() string {
inputs := make([]string, len(method.Inputs))
for i, input := range method.Inputs {
inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type)
}
outputs := make([]string, len(m.Outputs))
for i, output := range m.Outputs {
outputs := make([]string, len(method.Outputs))
for i, output := range method.Outputs {
if len(output.Name) > 0 {
outputs[i] = fmt.Sprintf("%v ", output.Name)
}
outputs[i] += output.Type.String()
}
constant := ""
if m.Const {
if method.Const {
constant = "constant "
}
return fmt.Sprintf("function %v(%v) %sreturns(%v)", m.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
}
func (m Method) Id() []byte {
return crypto.Keccak256([]byte(m.Sig()))[:4]
func (method Method) Id() []byte {
return crypto.Keccak256([]byte(method.Sig()))[:4]
}

View File

@@ -21,57 +21,32 @@ import (
"reflect"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
)
var (
big_t = reflect.TypeOf(big.Int{})
ubig_t = reflect.TypeOf(big.Int{})
byte_t = reflect.TypeOf(byte(0))
byte_ts = reflect.TypeOf([]byte(nil))
uint_t = reflect.TypeOf(uint(0))
uint8_t = reflect.TypeOf(uint8(0))
uint16_t = reflect.TypeOf(uint16(0))
uint32_t = reflect.TypeOf(uint32(0))
uint64_t = reflect.TypeOf(uint64(0))
int_t = reflect.TypeOf(int(0))
int8_t = reflect.TypeOf(int8(0))
int16_t = reflect.TypeOf(int16(0))
int32_t = reflect.TypeOf(int32(0))
int64_t = reflect.TypeOf(int64(0))
hash_t = reflect.TypeOf(common.Hash{})
address_t = reflect.TypeOf(common.Address{})
uint_ts = reflect.TypeOf([]uint(nil))
uint8_ts = reflect.TypeOf([]uint8(nil))
uint16_ts = reflect.TypeOf([]uint16(nil))
uint32_ts = reflect.TypeOf([]uint32(nil))
uint64_ts = reflect.TypeOf([]uint64(nil))
ubig_ts = reflect.TypeOf([]*big.Int(nil))
int_ts = reflect.TypeOf([]int(nil))
int8_ts = reflect.TypeOf([]int8(nil))
int16_ts = reflect.TypeOf([]int16(nil))
int32_ts = reflect.TypeOf([]int32(nil))
int64_ts = reflect.TypeOf([]int64(nil))
big_ts = reflect.TypeOf([]*big.Int(nil))
big_t = reflect.TypeOf(&big.Int{})
derefbig_t = reflect.TypeOf(big.Int{})
uint8_t = reflect.TypeOf(uint8(0))
uint16_t = reflect.TypeOf(uint16(0))
uint32_t = reflect.TypeOf(uint32(0))
uint64_t = reflect.TypeOf(uint64(0))
int_t = reflect.TypeOf(int(0))
int8_t = reflect.TypeOf(int8(0))
int16_t = reflect.TypeOf(int16(0))
int32_t = reflect.TypeOf(int32(0))
int64_t = reflect.TypeOf(int64(0))
address_t = reflect.TypeOf(common.Address{})
int_ts = reflect.TypeOf([]int(nil))
int8_ts = reflect.TypeOf([]int8(nil))
int16_ts = reflect.TypeOf([]int16(nil))
int32_ts = reflect.TypeOf([]int32(nil))
int64_ts = reflect.TypeOf([]int64(nil))
)
// U256 converts a big Int into a 256bit EVM number.
func U256(n *big.Int) []byte {
return common.LeftPadBytes(common.U256(n).Bytes(), 32)
}
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
func packNum(value reflect.Value) []byte {
switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return U256(new(big.Int).SetUint64(value.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return U256(big.NewInt(value.Int()))
case reflect.Ptr:
return U256(value.Interface().(*big.Int))
}
return nil
return math.PaddedBigBytes(math.U256(n), 32)
}
// checks whether the given reflect value is signed. This also works for slices with a number type

View File

@@ -18,7 +18,6 @@ package abi
import (
"bytes"
"math"
"math/big"
"reflect"
"testing"
@@ -34,43 +33,6 @@ func TestNumberTypes(t *testing.T) {
}
}
func TestPackNumber(t *testing.T) {
tests := []struct {
value reflect.Value
packed []byte
}{
// Protocol limits
{reflect.ValueOf(0), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
{reflect.ValueOf(1), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
{reflect.ValueOf(-1), []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}},
// Type corner cases
{reflect.ValueOf(uint8(math.MaxUint8)), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255}},
{reflect.ValueOf(uint16(math.MaxUint16)), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255}},
{reflect.ValueOf(uint32(math.MaxUint32)), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255}},
{reflect.ValueOf(uint64(math.MaxUint64)), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255}},
{reflect.ValueOf(int8(math.MaxInt8)), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127}},
{reflect.ValueOf(int16(math.MaxInt16)), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255}},
{reflect.ValueOf(int32(math.MaxInt32)), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 255}},
{reflect.ValueOf(int64(math.MaxInt64)), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 255, 255, 255, 255, 255}},
{reflect.ValueOf(int8(math.MinInt8)), []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128}},
{reflect.ValueOf(int16(math.MinInt16)), []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0}},
{reflect.ValueOf(int32(math.MinInt32)), []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 0, 0}},
{reflect.ValueOf(int64(math.MinInt64)), []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0}},
}
for i, tt := range tests {
packed := packNum(tt.value)
if !bytes.Equal(packed, tt.packed) {
t.Errorf("test %d: pack mismatch: have %x, want %x", i, packed, tt.packed)
}
}
if packed := packNum(reflect.ValueOf("string")); packed != nil {
t.Errorf("expected 'string' to pack to nil. got %x instead", packed)
}
}
func TestSigned(t *testing.T) {
if isSigned(reflect.ValueOf(uint(10))) {
t.Error("signed")

81
accounts/abi/pack.go Normal file
View File

@@ -0,0 +1,81 @@
// Copyright 2016 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 abi
import (
"math/big"
"reflect"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
)
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
// bytes slice
func packBytesSlice(bytes []byte, l int) []byte {
len := packNum(reflect.ValueOf(l))
return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...)
}
// packElement packs the given reflect value according to the abi specification in
// t.
func packElement(t Type, reflectValue reflect.Value) []byte {
switch t.T {
case IntTy, UintTy:
return packNum(reflectValue)
case StringTy:
return packBytesSlice([]byte(reflectValue.String()), reflectValue.Len())
case AddressTy:
if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue)
}
return common.LeftPadBytes(reflectValue.Bytes(), 32)
case BoolTy:
if reflectValue.Bool() {
return math.PaddedBigBytes(common.Big1, 32)
}
return math.PaddedBigBytes(common.Big0, 32)
case BytesTy:
if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue)
}
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
case FixedBytesTy, FunctionTy:
if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue)
}
return common.RightPadBytes(reflectValue.Bytes(), 32)
default:
panic("abi: fatal error")
}
}
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
func packNum(value reflect.Value) []byte {
switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return U256(new(big.Int).SetUint64(value.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return U256(big.NewInt(value.Int()))
case reflect.Ptr:
return U256(value.Interface().(*big.Int))
default:
panic("abi: fatal error")
}
}

443
accounts/abi/pack_test.go Normal file
View File

@@ -0,0 +1,443 @@
// Copyright 2017 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 abi
import (
"bytes"
"math"
"math/big"
"reflect"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
)
func TestPack(t *testing.T) {
for i, test := range []struct {
typ string
input interface{}
output []byte
}{
{
"uint8",
uint8(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint8[]",
[]uint8{1, 2},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint16",
uint16(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint16[]",
[]uint16{1, 2},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint32",
uint32(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint32[]",
[]uint32{1, 2},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint64",
uint64(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint64[]",
[]uint64{1, 2},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint256",
big.NewInt(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"uint256[]",
[]*big.Int{big.NewInt(1), big.NewInt(2)},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int8",
int8(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int8[]",
[]int8{1, 2},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int16",
int16(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int16[]",
[]int16{1, 2},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int32",
int32(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int32[]",
[]int32{1, 2},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int64",
int64(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int64[]",
[]int64{1, 2},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int256",
big.NewInt(2),
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"),
},
{
"int256[]",
[]*big.Int{big.NewInt(1), big.NewInt(2)},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"),
},
{
"bytes1",
[1]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes2",
[2]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes3",
[3]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes4",
[4]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes5",
[5]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes6",
[6]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes7",
[7]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes8",
[8]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes9",
[9]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes10",
[10]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes11",
[11]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes12",
[12]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes13",
[13]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes14",
[14]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes15",
[15]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes16",
[16]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes17",
[17]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes18",
[18]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes19",
[19]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes20",
[20]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes21",
[21]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes22",
[22]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes23",
[23]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes24",
[24]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes24",
[24]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes25",
[25]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes26",
[26]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes27",
[27]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes28",
[28]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes29",
[29]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes30",
[30]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes31",
[31]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"bytes32",
[32]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"uint32[2][3][4]",
[4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"),
},
{
"address[]",
[]common.Address{{1}, {2}},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"),
},
{
"bytes32[]",
[]common.Hash{{1}, {2}},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"),
},
{
"function",
[24]byte{1},
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
"string",
"foobar",
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"),
},
} {
typ, err := NewType(test.typ)
if err != nil {
t.Fatalf("%v failed. Unexpected parse error: %v", i, err)
}
output, err := typ.pack(reflect.ValueOf(test.input))
if err != nil {
t.Fatalf("%v failed. Unexpected pack error: %v", i, err)
}
if !bytes.Equal(output, test.output) {
t.Errorf("%d failed. Expected bytes: '%x' Got: '%x'", i, test.output, output)
}
}
}
func TestMethodPack(t *testing.T) {
abi, err := JSON(strings.NewReader(jsondata2))
if err != nil {
t.Fatal(err)
}
sig := abi.Methods["slice"].Id()
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
packed, err := abi.Pack("slice", []uint32{1, 2})
if err != nil {
t.Error(err)
}
if !bytes.Equal(packed, sig) {
t.Errorf("expected %x got %x", sig, packed)
}
var addrA, addrB = common.Address{1}, common.Address{2}
sig = abi.Methods["sliceAddress"].Id()
sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
sig = append(sig, common.LeftPadBytes(addrA[:], 32)...)
sig = append(sig, common.LeftPadBytes(addrB[:], 32)...)
packed, err = abi.Pack("sliceAddress", []common.Address{addrA, addrB})
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(packed, sig) {
t.Errorf("expected %x got %x", sig, packed)
}
var addrC, addrD = common.Address{3}, common.Address{4}
sig = abi.Methods["sliceMultiAddress"].Id()
sig = append(sig, common.LeftPadBytes([]byte{64}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{160}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
sig = append(sig, common.LeftPadBytes(addrA[:], 32)...)
sig = append(sig, common.LeftPadBytes(addrB[:], 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
sig = append(sig, common.LeftPadBytes(addrC[:], 32)...)
sig = append(sig, common.LeftPadBytes(addrD[:], 32)...)
packed, err = abi.Pack("sliceMultiAddress", []common.Address{addrA, addrB}, []common.Address{addrC, addrD})
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(packed, sig) {
t.Errorf("expected %x got %x", sig, packed)
}
sig = abi.Methods["slice256"].Id()
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
packed, err = abi.Pack("slice256", []*big.Int{big.NewInt(1), big.NewInt(2)})
if err != nil {
t.Error(err)
}
if !bytes.Equal(packed, sig) {
t.Errorf("expected %x got %x", sig, packed)
}
}
func TestPackNumber(t *testing.T) {
tests := []struct {
value reflect.Value
packed []byte
}{
// Protocol limits
{reflect.ValueOf(0), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000")},
{reflect.ValueOf(1), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")},
{reflect.ValueOf(-1), common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")},
// Type corner cases
{reflect.ValueOf(uint8(math.MaxUint8)), common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000ff")},
{reflect.ValueOf(uint16(math.MaxUint16)), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000ffff")},
{reflect.ValueOf(uint32(math.MaxUint32)), common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000ffffffff")},
{reflect.ValueOf(uint64(math.MaxUint64)), common.Hex2Bytes("000000000000000000000000000000000000000000000000ffffffffffffffff")},
{reflect.ValueOf(int8(math.MaxInt8)), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000007f")},
{reflect.ValueOf(int16(math.MaxInt16)), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000007fff")},
{reflect.ValueOf(int32(math.MaxInt32)), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000007fffffff")},
{reflect.ValueOf(int64(math.MaxInt64)), common.Hex2Bytes("0000000000000000000000000000000000000000000000007fffffffffffffff")},
{reflect.ValueOf(int8(math.MinInt8)), common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80")},
{reflect.ValueOf(int16(math.MinInt16)), common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000")},
{reflect.ValueOf(int32(math.MinInt32)), common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000")},
{reflect.ValueOf(int64(math.MinInt64)), common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000")},
}
for i, tt := range tests {
packed := packNum(tt.value)
if !bytes.Equal(packed, tt.packed) {
t.Errorf("test %d: pack mismatch: have %x, want %x", i, packed, tt.packed)
}
}
}

View File

@@ -1,65 +0,0 @@
// Copyright 2016 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 abi
import (
"reflect"
"github.com/ethereum/go-ethereum/common"
)
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
// bytes slice
func packBytesSlice(bytes []byte, l int) []byte {
len := packNum(reflect.ValueOf(l))
return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...)
}
// packElement packs the given reflect value according to the abi specification in
// t.
func packElement(t Type, reflectValue reflect.Value) []byte {
switch t.T {
case IntTy, UintTy:
return packNum(reflectValue)
case StringTy:
return packBytesSlice([]byte(reflectValue.String()), reflectValue.Len())
case AddressTy:
if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue)
}
return common.LeftPadBytes(reflectValue.Bytes(), 32)
case BoolTy:
if reflectValue.Bool() {
return common.LeftPadBytes(common.Big1.Bytes(), 32)
} else {
return common.LeftPadBytes(common.Big0.Bytes(), 32)
}
case BytesTy:
if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue)
}
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
case FixedBytesTy:
if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue)
}
return common.RightPadBytes(reflectValue.Bytes(), 32)
}
panic("abi: fatal error")
}

View File

@@ -24,7 +24,7 @@ import (
// indirect recursively dereferences the value until it either gets the value
// or finds a big.Int
func indirect(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr && v.Elem().Type() != big_t {
if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbig_t {
return indirect(v.Elem())
}
return v
@@ -32,30 +32,30 @@ func indirect(v reflect.Value) reflect.Value {
// reflectIntKind returns the reflect using the given size and
// unsignedness.
func reflectIntKind(unsigned bool, size int) reflect.Kind {
func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) {
switch size {
case 8:
if unsigned {
return reflect.Uint8
return reflect.Uint8, uint8_t
}
return reflect.Int8
return reflect.Int8, int8_t
case 16:
if unsigned {
return reflect.Uint16
return reflect.Uint16, uint16_t
}
return reflect.Int16
return reflect.Int16, int16_t
case 32:
if unsigned {
return reflect.Uint32
return reflect.Uint32, uint32_t
}
return reflect.Int32
return reflect.Int32, int32_t
case 64:
if unsigned {
return reflect.Uint64
return reflect.Uint64, uint64_t
}
return reflect.Int64
return reflect.Int64, int64_t
}
return reflect.Ptr
return reflect.Ptr, big_t
}
// mustArrayToBytesSlice creates a new byte slice with the exact same size as value
@@ -73,15 +73,9 @@ func mustArrayToByteSlice(value reflect.Value) reflect.Value {
func set(dst, src reflect.Value, output Argument) error {
dstType := dst.Type()
srcType := src.Type()
switch {
case dstType.AssignableTo(src.Type()):
case dstType.AssignableTo(srcType):
dst.Set(src)
case dstType.Kind() == reflect.Array && srcType.Kind() == reflect.Slice:
if dst.Len() < output.Type.SliceSize {
return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.SliceSize, dst.Len())
}
reflect.Copy(dst, src)
case dstType.Kind() == reflect.Interface:
dst.Set(src)
case dstType.Kind() == reflect.Ptr:
@@ -91,3 +85,28 @@ func set(dst, src reflect.Value, output Argument) error {
}
return nil
}
// requireAssignable assures that `dest` is a pointer and it's not an interface.
func requireAssignable(dst, src reflect.Value) error {
if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface {
return fmt.Errorf("abi: cannot unmarshal %v into %v", src.Type(), dst.Type())
}
return nil
}
// requireUnpackKind verifies preconditions for unpacking `args` into `kind`
func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
args Arguments) error {
switch k {
case reflect.Struct:
case reflect.Slice, reflect.Array:
if minLen := args.LengthNonIndexed(); v.Len() < minLen {
return fmt.Errorf("abi: insufficient number of elements in the list/array for unpack, want %d, got %d",
minLen, v.Len())
}
default:
return fmt.Errorf("abi: cannot unmarshal tuple into %v", t)
}
return nil
}

View File

@@ -21,26 +21,27 @@ import (
"reflect"
"regexp"
"strconv"
"strings"
)
// Type enumerator
const (
IntTy byte = iota
UintTy
BoolTy
StringTy
SliceTy
ArrayTy
AddressTy
FixedBytesTy
BytesTy
HashTy
RealTy
FixedPointTy
FunctionTy
)
// Type is the reflection of the supported argument type
type Type struct {
IsSlice, IsArray bool
SliceSize int
Elem *Type
Kind reflect.Kind
@@ -52,81 +53,86 @@ type Type struct {
}
var (
// fullTypeRegex parses the abi types
//
// Types can be in the format of:
//
// Input = Type [ "[" [ Number ] "]" ] Name .
// Type = [ "u" ] "int" [ Number ] .
//
// Examples:
//
// string int uint real
// string32 int8 uint8 uint[]
// address int256 uint256 real[2]
fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?")
// typeRegex parses the abi sub types
typeRegex = regexp.MustCompile("([a-zA-Z]+)([0-9]*)?")
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
)
// NewType creates a new reflection type of abi type given in t.
func NewType(t string) (typ Type, err error) {
res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0]
// check if type is slice and parse type.
switch {
case res[3] != "":
// err is ignored. Already checked for number through the regexp
typ.SliceSize, _ = strconv.Atoi(res[3])
typ.IsArray = true
case res[2] != "":
typ.IsSlice, typ.SliceSize = true, -1
case res[0] == "":
return Type{}, fmt.Errorf("abi: type parse error: %s", t)
// check that array brackets are equal if they exist
if strings.Count(t, "[") != strings.Count(t, "]") {
return Type{}, fmt.Errorf("invalid arg type in abi")
}
if typ.IsArray || typ.IsSlice {
sliceType, err := NewType(res[1])
typ.stringKind = t
// if there are brackets, get ready to go into slice/array mode and
// recursively create the type
if strings.Count(t, "[") != 0 {
i := strings.LastIndex(t, "[")
// recursively embed the type
embeddedType, err := NewType(t[:i])
if err != nil {
return Type{}, err
}
typ.Elem = &sliceType
typ.stringKind = sliceType.stringKind + t[len(res[1]):]
return typ, nil
}
// grab the last cell and create a type from there
sliced := t[i:]
// grab the slice size with regexp
re := regexp.MustCompile("[0-9]+")
intz := re.FindAllString(sliced, -1)
if len(intz) == 0 {
// is a slice
typ.T = SliceTy
typ.Kind = reflect.Slice
typ.Elem = &embeddedType
typ.Type = reflect.SliceOf(embeddedType.Type)
} else if len(intz) == 1 {
// is a array
typ.T = ArrayTy
typ.Kind = reflect.Array
typ.Elem = &embeddedType
typ.Size, err = strconv.Atoi(intz[0])
if err != nil {
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
}
typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
} else {
return Type{}, fmt.Errorf("invalid formatting of array type")
}
return typ, err
}
// parse the type and size of the abi-type.
parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0]
// varSize is the size of the variable
var varSize int
if len(parsedType[2]) > 0 {
if len(parsedType[3]) > 0 {
var err error
varSize, err = strconv.Atoi(parsedType[2])
if err != nil {
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
}
} else {
if parsedType[0] == "uint" || parsedType[0] == "int" {
// this should fail because it means that there's something wrong with
// the abi type (the compiler should always format it to the size...always)
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
}
}
// varType is the parsed abi type
varType := parsedType[1]
// substitute canonical integer
if varSize == 0 && (varType == "int" || varType == "uint") {
varSize = 256
t += "256"
}
typ.stringKind = t
switch varType {
switch varType := parsedType[1]; varType {
case "int":
typ.Kind = reflectIntKind(false, varSize)
typ.Type = big_t
typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
typ.Size = varSize
typ.T = IntTy
case "uint":
typ.Kind = reflectIntKind(true, varSize)
typ.Type = ubig_t
typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
typ.Size = varSize
typ.T = UintTy
case "bool":
typ.Kind = reflect.Bool
typ.T = BoolTy
typ.Type = reflect.TypeOf(bool(false))
case "address":
typ.Kind = reflect.Array
typ.Type = address_t
@@ -134,20 +140,24 @@ func NewType(t string) (typ Type, err error) {
typ.T = AddressTy
case "string":
typ.Kind = reflect.String
typ.Size = -1
typ.Type = reflect.TypeOf("")
typ.T = StringTy
case "bytes":
sliceType, _ := NewType("uint8")
typ.Elem = &sliceType
if varSize == 0 {
typ.IsSlice = true
typ.T = BytesTy
typ.SliceSize = -1
typ.Kind = reflect.Slice
typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0)))
} else {
typ.IsArray = true
typ.T = FixedBytesTy
typ.SliceSize = varSize
typ.Kind = reflect.Array
typ.Size = varSize
typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0)))
}
case "function":
typ.Kind = reflect.Array
typ.T = FunctionTy
typ.Size = 24
typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0)))
default:
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
}
@@ -168,7 +178,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
return nil, err
}
if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy {
if t.T == SliceTy || t.T == ArrayTy {
var packed []byte
for i := 0; i < v.Len(); i++ {
@@ -178,18 +188,17 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
}
packed = append(packed, val...)
}
if t.IsSlice {
if t.T == SliceTy {
return packBytesSlice(packed, v.Len()), nil
} else if t.IsArray {
} else if t.T == ArrayTy {
return packed, nil
}
}
return packElement(t, v), nil
}
// requireLengthPrefix returns whether the type requires any sort of length
// prefixing.
func (t Type) requiresLengthPrefix() bool {
return t.T != FixedBytesTy && (t.T == StringTy || t.T == BytesTy || t.IsSlice)
return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
}

280
accounts/abi/type_test.go Normal file
View File

@@ -0,0 +1,280 @@
// Copyright 2016 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 abi
import (
"math/big"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common"
)
// typeWithoutStringer is a alias for the Type type which simply doesn't implement
// the stringer interface to allow printing type details in the tests below.
type typeWithoutStringer Type
// Tests that all allowed types get recognized by the type parser.
func TestTypeRegexp(t *testing.T) {
tests := []struct {
blob string
kind Type
}{
{"bool", Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}},
{"bool[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool(nil)), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}},
{"bool[2]", Type{Size: 2, Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}},
{"bool[2][]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][]"}},
{"bool[][]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][]"}},
{"bool[][2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][2]"}},
{"bool[2][2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][2]"}},
{"bool[2][][2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][][2]bool{}), Elem: &Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][]"}, stringKind: "bool[2][][2]"}},
{"bool[2][2][2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][2]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[2]"}, stringKind: "bool[2][2]"}, stringKind: "bool[2][2][2]"}},
{"bool[][][]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][]"}, stringKind: "bool[][][]"}},
{"bool[][2][]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][2][]bool{}), Elem: &Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]bool{}), Elem: &Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]bool{}), Elem: &Type{Kind: reflect.Bool, T: BoolTy, Type: reflect.TypeOf(bool(false)), stringKind: "bool"}, stringKind: "bool[]"}, stringKind: "bool[][2]"}, stringKind: "bool[][2][]"}},
{"int8", Type{Kind: reflect.Int8, Type: int8_t, Size: 8, T: IntTy, stringKind: "int8"}},
{"int16", Type{Kind: reflect.Int16, Type: int16_t, Size: 16, T: IntTy, stringKind: "int16"}},
{"int32", Type{Kind: reflect.Int32, Type: int32_t, Size: 32, T: IntTy, stringKind: "int32"}},
{"int64", Type{Kind: reflect.Int64, Type: int64_t, Size: 64, T: IntTy, stringKind: "int64"}},
{"int256", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}},
{"int8[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int8{}), Elem: &Type{Kind: reflect.Int8, Type: int8_t, Size: 8, T: IntTy, stringKind: "int8"}, stringKind: "int8[]"}},
{"int8[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int8{}), Elem: &Type{Kind: reflect.Int8, Type: int8_t, Size: 8, T: IntTy, stringKind: "int8"}, stringKind: "int8[2]"}},
{"int16[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int16{}), Elem: &Type{Kind: reflect.Int16, Type: int16_t, Size: 16, T: IntTy, stringKind: "int16"}, stringKind: "int16[]"}},
{"int16[2]", Type{Size: 2, Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]int16{}), Elem: &Type{Kind: reflect.Int16, Type: int16_t, Size: 16, T: IntTy, stringKind: "int16"}, stringKind: "int16[2]"}},
{"int32[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int32{}), Elem: &Type{Kind: reflect.Int32, Type: int32_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[]"}},
{"int32[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int32{}), Elem: &Type{Kind: reflect.Int32, Type: int32_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[2]"}},
{"int64[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]int64{}), Elem: &Type{Kind: reflect.Int64, Type: int64_t, Size: 64, T: IntTy, stringKind: "int64"}, stringKind: "int64[]"}},
{"int64[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]int64{}), Elem: &Type{Kind: reflect.Int64, Type: int64_t, Size: 64, T: IntTy, stringKind: "int64"}, stringKind: "int64[2]"}},
{"int256[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[]"}},
{"int256[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[2]"}},
{"uint8", Type{Kind: reflect.Uint8, Type: uint8_t, Size: 8, T: UintTy, stringKind: "uint8"}},
{"uint16", Type{Kind: reflect.Uint16, Type: uint16_t, Size: 16, T: UintTy, stringKind: "uint16"}},
{"uint32", Type{Kind: reflect.Uint32, Type: uint32_t, Size: 32, T: UintTy, stringKind: "uint32"}},
{"uint64", Type{Kind: reflect.Uint64, Type: uint64_t, Size: 64, T: UintTy, stringKind: "uint64"}},
{"uint256", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: UintTy, stringKind: "uint256"}},
{"uint8[]", Type{Kind: reflect.Slice, T: SliceTy, Type: reflect.TypeOf([]uint8{}), Elem: &Type{Kind: reflect.Uint8, Type: uint8_t, Size: 8, T: UintTy, stringKind: "uint8"}, stringKind: "uint8[]"}},
{"uint8[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint8{}), Elem: &Type{Kind: reflect.Uint8, Type: uint8_t, Size: 8, T: UintTy, stringKind: "uint8"}, stringKind: "uint8[2]"}},
{"uint16[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint16{}), Elem: &Type{Kind: reflect.Uint16, Type: uint16_t, Size: 16, T: UintTy, stringKind: "uint16"}, stringKind: "uint16[]"}},
{"uint16[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint16{}), Elem: &Type{Kind: reflect.Uint16, Type: uint16_t, Size: 16, T: UintTy, stringKind: "uint16"}, stringKind: "uint16[2]"}},
{"uint32[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint32{}), Elem: &Type{Kind: reflect.Uint32, Type: uint32_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[]"}},
{"uint32[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint32{}), Elem: &Type{Kind: reflect.Uint32, Type: uint32_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[2]"}},
{"uint64[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]uint64{}), Elem: &Type{Kind: reflect.Uint64, Type: uint64_t, Size: 64, T: UintTy, stringKind: "uint64"}, stringKind: "uint64[]"}},
{"uint64[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]uint64{}), Elem: &Type{Kind: reflect.Uint64, Type: uint64_t, Size: 64, T: UintTy, stringKind: "uint64"}, stringKind: "uint64[2]"}},
{"uint256[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]*big.Int{}), Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[]"}},
{"uint256[2]", Type{Kind: reflect.Array, T: ArrayTy, Type: reflect.TypeOf([2]*big.Int{}), Size: 2, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[2]"}},
{"bytes32", Type{Kind: reflect.Array, T: FixedBytesTy, Size: 32, Type: reflect.TypeOf([32]byte{}), stringKind: "bytes32"}},
{"bytes[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][]byte{}), Elem: &Type{Kind: reflect.Slice, Type: reflect.TypeOf([]byte{}), T: BytesTy, stringKind: "bytes"}, stringKind: "bytes[]"}},
{"bytes[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][]byte{}), Elem: &Type{T: BytesTy, Type: reflect.TypeOf([]byte{}), Kind: reflect.Slice, stringKind: "bytes"}, stringKind: "bytes[2]"}},
{"bytes32[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([][32]byte{}), Elem: &Type{Kind: reflect.Array, Type: reflect.TypeOf([32]byte{}), T: FixedBytesTy, Size: 32, stringKind: "bytes32"}, stringKind: "bytes32[]"}},
{"bytes32[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2][32]byte{}), Elem: &Type{Kind: reflect.Array, T: FixedBytesTy, Size: 32, Type: reflect.TypeOf([32]byte{}), stringKind: "bytes32"}, stringKind: "bytes32[2]"}},
{"string", Type{Kind: reflect.String, T: StringTy, Type: reflect.TypeOf(""), stringKind: "string"}},
{"string[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]string{}), Elem: &Type{Kind: reflect.String, Type: reflect.TypeOf(""), T: StringTy, stringKind: "string"}, stringKind: "string[]"}},
{"string[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]string{}), Elem: &Type{Kind: reflect.String, T: StringTy, Type: reflect.TypeOf(""), stringKind: "string"}, stringKind: "string[2]"}},
{"address", Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}},
{"address[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]common.Address{}), Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}},
{"address[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]common.Address{}), Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}},
// TODO when fixed types are implemented properly
// {"fixed", Type{}},
// {"fixed128x128", Type{}},
// {"fixed[]", Type{}},
// {"fixed[2]", Type{}},
// {"fixed128x128[]", Type{}},
// {"fixed128x128[2]", Type{}},
}
for _, tt := range tests {
typ, err := NewType(tt.blob)
if err != nil {
t.Errorf("type %q: failed to parse type string: %v", tt.blob, err)
}
if !reflect.DeepEqual(typ, tt.kind) {
t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", tt.blob, spew.Sdump(typeWithoutStringer(typ)), spew.Sdump(typeWithoutStringer(tt.kind)))
}
}
}
func TestTypeCheck(t *testing.T) {
for i, test := range []struct {
typ string
input interface{}
err string
}{
{"uint", big.NewInt(1), "unsupported arg type: uint"},
{"int", big.NewInt(1), "unsupported arg type: int"},
{"uint256", big.NewInt(1), ""},
{"uint256[][3][]", [][3][]*big.Int{{{}}}, ""},
{"uint256[][][3]", [3][][]*big.Int{{{}}}, ""},
{"uint256[3][][]", [][][3]*big.Int{{{}}}, ""},
{"uint256[3][3][3]", [3][3][3]*big.Int{{{}}}, ""},
{"uint8[][]", [][]uint8{}, ""},
{"int256", big.NewInt(1), ""},
{"uint8", uint8(1), ""},
{"uint16", uint16(1), ""},
{"uint32", uint32(1), ""},
{"uint64", uint64(1), ""},
{"int8", int8(1), ""},
{"int16", int16(1), ""},
{"int32", int32(1), ""},
{"int64", int64(1), ""},
{"uint24", big.NewInt(1), ""},
{"uint40", big.NewInt(1), ""},
{"uint48", big.NewInt(1), ""},
{"uint56", big.NewInt(1), ""},
{"uint72", big.NewInt(1), ""},
{"uint80", big.NewInt(1), ""},
{"uint88", big.NewInt(1), ""},
{"uint96", big.NewInt(1), ""},
{"uint104", big.NewInt(1), ""},
{"uint112", big.NewInt(1), ""},
{"uint120", big.NewInt(1), ""},
{"uint128", big.NewInt(1), ""},
{"uint136", big.NewInt(1), ""},
{"uint144", big.NewInt(1), ""},
{"uint152", big.NewInt(1), ""},
{"uint160", big.NewInt(1), ""},
{"uint168", big.NewInt(1), ""},
{"uint176", big.NewInt(1), ""},
{"uint184", big.NewInt(1), ""},
{"uint192", big.NewInt(1), ""},
{"uint200", big.NewInt(1), ""},
{"uint208", big.NewInt(1), ""},
{"uint216", big.NewInt(1), ""},
{"uint224", big.NewInt(1), ""},
{"uint232", big.NewInt(1), ""},
{"uint240", big.NewInt(1), ""},
{"uint248", big.NewInt(1), ""},
{"int24", big.NewInt(1), ""},
{"int40", big.NewInt(1), ""},
{"int48", big.NewInt(1), ""},
{"int56", big.NewInt(1), ""},
{"int72", big.NewInt(1), ""},
{"int80", big.NewInt(1), ""},
{"int88", big.NewInt(1), ""},
{"int96", big.NewInt(1), ""},
{"int104", big.NewInt(1), ""},
{"int112", big.NewInt(1), ""},
{"int120", big.NewInt(1), ""},
{"int128", big.NewInt(1), ""},
{"int136", big.NewInt(1), ""},
{"int144", big.NewInt(1), ""},
{"int152", big.NewInt(1), ""},
{"int160", big.NewInt(1), ""},
{"int168", big.NewInt(1), ""},
{"int176", big.NewInt(1), ""},
{"int184", big.NewInt(1), ""},
{"int192", big.NewInt(1), ""},
{"int200", big.NewInt(1), ""},
{"int208", big.NewInt(1), ""},
{"int216", big.NewInt(1), ""},
{"int224", big.NewInt(1), ""},
{"int232", big.NewInt(1), ""},
{"int240", big.NewInt(1), ""},
{"int248", big.NewInt(1), ""},
{"uint30", uint8(1), "abi: cannot use uint8 as type ptr as argument"},
{"uint8", uint16(1), "abi: cannot use uint16 as type uint8 as argument"},
{"uint8", uint32(1), "abi: cannot use uint32 as type uint8 as argument"},
{"uint8", uint64(1), "abi: cannot use uint64 as type uint8 as argument"},
{"uint8", int8(1), "abi: cannot use int8 as type uint8 as argument"},
{"uint8", int16(1), "abi: cannot use int16 as type uint8 as argument"},
{"uint8", int32(1), "abi: cannot use int32 as type uint8 as argument"},
{"uint8", int64(1), "abi: cannot use int64 as type uint8 as argument"},
{"uint16", uint16(1), ""},
{"uint16", uint8(1), "abi: cannot use uint8 as type uint16 as argument"},
{"uint16[]", []uint16{1, 2, 3}, ""},
{"uint16[]", [3]uint16{1, 2, 3}, ""},
{"uint16[]", []uint32{1, 2, 3}, "abi: cannot use []uint32 as type [0]uint16 as argument"},
{"uint16[3]", [3]uint32{1, 2, 3}, "abi: cannot use [3]uint32 as type [3]uint16 as argument"},
{"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
{"uint16[3]", []uint16{1, 2, 3}, ""},
{"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
{"address[]", []common.Address{{1}}, ""},
{"address[1]", []common.Address{{1}}, ""},
{"address[1]", [1]common.Address{{1}}, ""},
{"address[2]", [1]common.Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"},
{"bytes32", [32]byte{}, ""},
{"bytes31", [31]byte{}, ""},
{"bytes30", [30]byte{}, ""},
{"bytes29", [29]byte{}, ""},
{"bytes28", [28]byte{}, ""},
{"bytes27", [27]byte{}, ""},
{"bytes26", [26]byte{}, ""},
{"bytes25", [25]byte{}, ""},
{"bytes24", [24]byte{}, ""},
{"bytes23", [23]byte{}, ""},
{"bytes22", [22]byte{}, ""},
{"bytes21", [21]byte{}, ""},
{"bytes20", [20]byte{}, ""},
{"bytes19", [19]byte{}, ""},
{"bytes18", [18]byte{}, ""},
{"bytes17", [17]byte{}, ""},
{"bytes16", [16]byte{}, ""},
{"bytes15", [15]byte{}, ""},
{"bytes14", [14]byte{}, ""},
{"bytes13", [13]byte{}, ""},
{"bytes12", [12]byte{}, ""},
{"bytes11", [11]byte{}, ""},
{"bytes10", [10]byte{}, ""},
{"bytes9", [9]byte{}, ""},
{"bytes8", [8]byte{}, ""},
{"bytes7", [7]byte{}, ""},
{"bytes6", [6]byte{}, ""},
{"bytes5", [5]byte{}, ""},
{"bytes4", [4]byte{}, ""},
{"bytes3", [3]byte{}, ""},
{"bytes2", [2]byte{}, ""},
{"bytes1", [1]byte{}, ""},
{"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"},
{"bytes32", common.Hash{1}, ""},
{"bytes31", common.Hash{1}, "abi: cannot use common.Hash as type [31]uint8 as argument"},
{"bytes31", [32]byte{}, "abi: cannot use [32]uint8 as type [31]uint8 as argument"},
{"bytes", []byte{0, 1}, ""},
{"bytes", [2]byte{0, 1}, "abi: cannot use array as type slice as argument"},
{"bytes", common.Hash{1}, "abi: cannot use array as type slice as argument"},
{"string", "hello world", ""},
{"string", string(""), ""},
{"string", []byte{}, "abi: cannot use slice as type string as argument"},
{"bytes32[]", [][32]byte{{}}, ""},
{"function", [24]byte{}, ""},
{"bytes20", common.Address{}, ""},
{"address", [20]byte{}, ""},
{"address", common.Address{}, ""},
} {
typ, err := NewType(test.typ)
if err != nil && len(test.err) == 0 {
t.Fatal("unexpected parse error:", err)
} else if err != nil && len(test.err) != 0 {
if err.Error() != test.err {
t.Errorf("%d failed. Expected err: '%v' got err: '%v'", i, test.err, err)
}
continue
}
err = typeCheck(typ, reflect.ValueOf(test.input))
if err != nil && len(test.err) == 0 {
t.Errorf("%d failed. Expected no err but got: %v", i, err)
continue
}
if err == nil && len(test.err) != 0 {
t.Errorf("%d failed. Expected err: %v but got none", i, test.err)
continue
}
if err != nil && len(test.err) != 0 && err.Error() != test.err {
t.Errorf("%d failed. Expected err: '%v' got err: '%v'", i, test.err, err)
}
}
}

230
accounts/abi/unpack.go Normal file
View File

@@ -0,0 +1,230 @@
// Copyright 2017 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 abi
import (
"encoding/binary"
"fmt"
"math/big"
"reflect"
"github.com/ethereum/go-ethereum/common"
)
// reads the integer based on its kind
func readInteger(kind reflect.Kind, b []byte) interface{} {
switch kind {
case reflect.Uint8:
return b[len(b)-1]
case reflect.Uint16:
return binary.BigEndian.Uint16(b[len(b)-2:])
case reflect.Uint32:
return binary.BigEndian.Uint32(b[len(b)-4:])
case reflect.Uint64:
return binary.BigEndian.Uint64(b[len(b)-8:])
case reflect.Int8:
return int8(b[len(b)-1])
case reflect.Int16:
return int16(binary.BigEndian.Uint16(b[len(b)-2:]))
case reflect.Int32:
return int32(binary.BigEndian.Uint32(b[len(b)-4:]))
case reflect.Int64:
return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
default:
return new(big.Int).SetBytes(b)
}
}
// reads a bool
func readBool(word []byte) (bool, error) {
for _, b := range word[:31] {
if b != 0 {
return false, errBadBool
}
}
switch word[31] {
case 0:
return false, nil
case 1:
return true, nil
default:
return false, errBadBool
}
}
// A function type is simply the address with the function selection signature at the end.
// This enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes)
func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
if t.T != FunctionTy {
return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array")
}
if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 {
err = fmt.Errorf("abi: got improperly encoded function type, got %v", word)
} else {
copy(funcTy[:], word[0:24])
}
return
}
// through reflection, creates a fixed array to be read from
func readFixedBytes(t Type, word []byte) (interface{}, error) {
if t.T != FixedBytesTy {
return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
}
// convert
array := reflect.New(t.Type).Elem()
reflect.Copy(array, reflect.ValueOf(word[0:t.Size]))
return array.Interface(), nil
}
func getFullElemSize(elem *Type) int {
//all other should be counted as 32 (slices have pointers to respective elements)
size := 32
//arrays wrap it, each element being the same size
for elem.T == ArrayTy {
size *= elem.Size
elem = elem.Elem
}
return size
}
// iteratively unpack elements
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
if size < 0 {
return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size)
}
if start+32*size > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size)
}
// this value will become our slice or our array, depending on the type
var refSlice reflect.Value
if t.T == SliceTy {
// declare our slice
refSlice = reflect.MakeSlice(t.Type, size, size)
} else if t.T == ArrayTy {
// declare our array
refSlice = reflect.New(t.Type).Elem()
} else {
return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage")
}
// Arrays have packed elements, resulting in longer unpack steps.
// Slices have just 32 bytes per element (pointing to the contents).
elemSize := 32
if t.T == ArrayTy {
elemSize = getFullElemSize(t.Elem)
}
for i, j := start, 0; j < size; i, j = i+elemSize, j+1 {
inter, err := toGoType(i, *t.Elem, output)
if err != nil {
return nil, err
}
// append the item to our reflect slice
refSlice.Index(j).Set(reflect.ValueOf(inter))
}
// return the interface
return refSlice.Interface(), nil
}
// toGoType parses the output bytes and recursively assigns the value of these bytes
// into a go type with accordance with the ABI spec.
func toGoType(index int, t Type, output []byte) (interface{}, error) {
if index+32 > len(output) {
return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32)
}
var (
returnOutput []byte
begin, end int
err error
)
// if we require a length prefix, find the beginning word and size returned.
if t.requiresLengthPrefix() {
begin, end, err = lengthPrefixPointsTo(index, output)
if err != nil {
return nil, err
}
} else {
returnOutput = output[index : index+32]
}
switch t.T {
case SliceTy:
return forEachUnpack(t, output, begin, end)
case ArrayTy:
return forEachUnpack(t, output, index, t.Size)
case StringTy: // variable arrays are written at the end of the return bytes
return string(output[begin : begin+end]), nil
case IntTy, UintTy:
return readInteger(t.Kind, returnOutput), nil
case BoolTy:
return readBool(returnOutput)
case AddressTy:
return common.BytesToAddress(returnOutput), nil
case HashTy:
return common.BytesToHash(returnOutput), nil
case BytesTy:
return output[begin : begin+end], nil
case FixedBytesTy:
return readFixedBytes(t, returnOutput)
case FunctionTy:
return readFunctionType(t, returnOutput)
default:
return nil, fmt.Errorf("abi: unknown type %v", t.T)
}
}
// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type.
func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32])
bigOffsetEnd.Add(bigOffsetEnd, common.Big32)
outputLength := big.NewInt(int64(len(output)))
if bigOffsetEnd.Cmp(outputLength) > 0 {
return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength)
}
if bigOffsetEnd.BitLen() > 63 {
return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd)
}
offsetEnd := int(bigOffsetEnd.Uint64())
lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd])
totalSize := big.NewInt(0)
totalSize.Add(totalSize, bigOffsetEnd)
totalSize.Add(totalSize, lengthBig)
if totalSize.BitLen() > 63 {
return 0, 0, fmt.Errorf("abi length larger than int64: %v", totalSize)
}
if totalSize.Cmp(outputLength) > 0 {
return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize)
}
start = int(bigOffsetEnd.Uint64())
length = int(lengthBig.Uint64())
return
}

800
accounts/abi/unpack_test.go Normal file
View File

@@ -0,0 +1,800 @@
// Copyright 2017 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 abi
import (
"bytes"
"encoding/hex"
"fmt"
"math/big"
"reflect"
"strconv"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
type unpackTest struct {
def string // ABI definition JSON
enc string // evm return data
want interface{} // the expected output
err string // empty or error if expected
}
func (test unpackTest) checkError(err error) error {
if err != nil {
if len(test.err) == 0 {
return fmt.Errorf("expected no err but got: %v", err)
} else if err.Error() != test.err {
return fmt.Errorf("expected err: '%v' got err: %q", test.err, err)
}
} else if len(test.err) > 0 {
return fmt.Errorf("expected err: %v but got none", test.err)
}
return nil
}
var unpackTests = []unpackTest{
{
def: `[{ "type": "bool" }]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: true,
},
{
def: `[{"type": "uint32"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: uint32(1),
},
{
def: `[{"type": "uint32"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: uint16(0),
err: "abi: cannot unmarshal uint32 in to uint16",
},
{
def: `[{"type": "uint17"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: uint16(0),
err: "abi: cannot unmarshal *big.Int in to uint16",
},
{
def: `[{"type": "uint17"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: big.NewInt(1),
},
{
def: `[{"type": "int32"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: int32(1),
},
{
def: `[{"type": "int32"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: int16(0),
err: "abi: cannot unmarshal int32 in to int16",
},
{
def: `[{"type": "int17"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: int16(0),
err: "abi: cannot unmarshal *big.Int in to int16",
},
{
def: `[{"type": "int17"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001",
want: big.NewInt(1),
},
{
def: `[{"type": "address"}]`,
enc: "0000000000000000000000000100000000000000000000000000000000000000",
want: common.Address{1},
},
{
def: `[{"type": "bytes32"}]`,
enc: "0100000000000000000000000000000000000000000000000000000000000000",
want: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
},
{
def: `[{"type": "bytes"}]`,
enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
want: common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
},
{
def: `[{"type": "bytes"}]`,
enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
want: [32]byte{},
err: "abi: cannot unmarshal []uint8 in to [32]uint8",
},
{
def: `[{"type": "bytes32"}]`,
enc: "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000",
want: []byte(nil),
err: "abi: cannot unmarshal [32]uint8 in to []uint8",
},
{
def: `[{"type": "bytes32"}]`,
enc: "0100000000000000000000000000000000000000000000000000000000000000",
want: [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
},
{
def: `[{"type": "function"}]`,
enc: "0100000000000000000000000000000000000000000000000000000000000000",
want: [24]byte{1},
},
// slices
{
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []uint8{1, 2},
},
{
def: `[{"type": "uint8[2]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2]uint8{1, 2},
},
// multi dimensional, if these pass, all types that don't require length prefix should pass
{
def: `[{"type": "uint8[][]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [][]uint8{{1, 2}, {1, 2}},
},
{
def: `[{"type": "uint8[2][2]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2][2]uint8{{1, 2}, {1, 2}},
},
{
def: `[{"type": "uint8[][2]"}]`,
enc: "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001",
want: [2][]uint8{{1}, {1}},
},
{
def: `[{"type": "uint8[2][]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [][2]uint8{{1, 2}},
},
{
def: `[{"type": "uint16[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []uint16{1, 2},
},
{
def: `[{"type": "uint16[2]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2]uint16{1, 2},
},
{
def: `[{"type": "uint32[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []uint32{1, 2},
},
{
def: `[{"type": "uint32[2]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2]uint32{1, 2},
},
{
def: `[{"type": "uint32[2][3][4]"}]`,
enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018",
want: [4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}},
},
{
def: `[{"type": "uint64[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []uint64{1, 2},
},
{
def: `[{"type": "uint64[2]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2]uint64{1, 2},
},
{
def: `[{"type": "uint256[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []*big.Int{big.NewInt(1), big.NewInt(2)},
},
{
def: `[{"type": "uint256[3]"}]`,
enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
},
{
def: `[{"type": "int8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []int8{1, 2},
},
{
def: `[{"type": "int8[2]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2]int8{1, 2},
},
{
def: `[{"type": "int16[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []int16{1, 2},
},
{
def: `[{"type": "int16[2]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2]int16{1, 2},
},
{
def: `[{"type": "int32[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []int32{1, 2},
},
{
def: `[{"type": "int32[2]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2]int32{1, 2},
},
{
def: `[{"type": "int64[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []int64{1, 2},
},
{
def: `[{"type": "int64[2]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: [2]int64{1, 2},
},
{
def: `[{"type": "int256[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: []*big.Int{big.NewInt(1), big.NewInt(2)},
},
{
def: `[{"type": "int256[3]"}]`,
enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
},
// struct outputs
{
def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
Int1 *big.Int
Int2 *big.Int
}{big.NewInt(1), big.NewInt(2)},
},
{
def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
Int1 *big.Int
Int2 *big.Int
}{},
err: "abi: multiple outputs mapping to the same struct field 'Int'",
},
{
def: `[{"name":"int","type":"int256"},{"name":"_int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
Int1 *big.Int
Int2 *big.Int
}{},
err: "abi: multiple outputs mapping to the same struct field 'Int'",
},
{
def: `[{"name":"Int","type":"int256"},{"name":"_int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
Int1 *big.Int
Int2 *big.Int
}{},
err: "abi: multiple outputs mapping to the same struct field 'Int'",
},
{
def: `[{"name":"Int","type":"int256"},{"name":"_","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
Int1 *big.Int
Int2 *big.Int
}{},
err: "abi: purely underscored output cannot unpack to struct",
},
}
func TestUnpack(t *testing.T) {
for i, test := range unpackTests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
abi, err := JSON(strings.NewReader(def))
if err != nil {
t.Fatalf("invalid ABI definition %s: %v", def, err)
}
encb, err := hex.DecodeString(test.enc)
if err != nil {
t.Fatalf("invalid hex: %s" + test.enc)
}
outptr := reflect.New(reflect.TypeOf(test.want))
err = abi.Unpack(outptr.Interface(), "method", encb)
if err := test.checkError(err); err != nil {
t.Errorf("test %d (%v) failed: %v", i, test.def, err)
return
}
out := outptr.Elem().Interface()
if !reflect.DeepEqual(test.want, out) {
t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, test.want, out)
}
})
}
}
type methodMultiOutput struct {
Int *big.Int
String string
}
func methodMultiReturn(require *require.Assertions) (ABI, []byte, methodMultiOutput) {
const definition = `[
{ "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]`
var expected = methodMultiOutput{big.NewInt(1), "hello"}
abi, err := JSON(strings.NewReader(definition))
require.NoError(err)
// using buff to make the code readable
buff := new(bytes.Buffer)
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
buff.Write(common.RightPadBytes([]byte(expected.String), 32))
return abi, buff.Bytes(), expected
}
func TestMethodMultiReturn(t *testing.T) {
type reversed struct {
String string
Int *big.Int
}
abi, data, expected := methodMultiReturn(require.New(t))
bigint := new(big.Int)
var testCases = []struct {
dest interface{}
expected interface{}
error string
name string
}{{
&methodMultiOutput{},
&expected,
"",
"Can unpack into structure",
}, {
&reversed{},
&reversed{expected.String, expected.Int},
"",
"Can unpack into reversed structure",
}, {
&[]interface{}{&bigint, new(string)},
&[]interface{}{&expected.Int, &expected.String},
"",
"Can unpack into a slice",
}, {
&[2]interface{}{&bigint, new(string)},
&[2]interface{}{&expected.Int, &expected.String},
"",
"Can unpack into an array",
}, {
&[]interface{}{new(int), new(int)},
&[]interface{}{&expected.Int, &expected.String},
"abi: cannot unmarshal *big.Int in to int",
"Can not unpack into a slice with wrong types",
}, {
&[]interface{}{new(int)},
&[]interface{}{},
"abi: insufficient number of elements in the list/array for unpack, want 2, got 1",
"Can not unpack into a slice with wrong types",
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
require := require.New(t)
err := abi.Unpack(tc.dest, "multi", data)
if tc.error == "" {
require.Nil(err, "Should be able to unpack method outputs.")
require.Equal(tc.expected, tc.dest)
} else {
require.EqualError(err, tc.error)
}
})
}
}
func TestMultiReturnWithArray(t *testing.T) {
const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
abi, err := JSON(strings.NewReader(definition))
if err != nil {
t.Fatal(err)
}
buff := new(bytes.Buffer)
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000009"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000008"))
ret1, ret1Exp := new([3]uint64), [3]uint64{9, 9, 9}
ret2, ret2Exp := new(uint64), uint64(8)
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(*ret1, ret1Exp) {
t.Error("array result", *ret1, "!= Expected", ret1Exp)
}
if *ret2 != ret2Exp {
t.Error("int result", *ret2, "!= Expected", ret2Exp)
}
}
func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
// Similar to TestMultiReturnWithArray, but with a special case in mind:
// values of nested static arrays count towards the size as well, and any element following
// after such nested array argument should be read with the correct offset,
// so that it does not read content from the previous array argument.
const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]`
abi, err := JSON(strings.NewReader(definition))
if err != nil {
t.Fatal(err)
}
buff := new(bytes.Buffer)
// construct the test array, each 3 char element is joined with 61 '0' chars,
// to from the ((3 + 61) * 0.5) = 32 byte elements in the array.
buff.Write(common.Hex2Bytes(strings.Join([]string{
"", //empty, to apply the 61-char separator to the first element as well.
"111", "112", "113", "121", "122", "123",
"211", "212", "213", "221", "222", "223",
"311", "312", "313", "321", "322", "323",
"411", "412", "413", "421", "422", "423",
}, "0000000000000000000000000000000000000000000000000000000000000")))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000009876"))
ret1, ret1Exp := new([4][2][3]uint64), [4][2][3]uint64{
{{0x111, 0x112, 0x113}, {0x121, 0x122, 0x123}},
{{0x211, 0x212, 0x213}, {0x221, 0x222, 0x223}},
{{0x311, 0x312, 0x313}, {0x321, 0x322, 0x323}},
{{0x411, 0x412, 0x413}, {0x421, 0x422, 0x423}},
}
ret2, ret2Exp := new(uint64), uint64(0x9876)
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(*ret1, ret1Exp) {
t.Error("array result", *ret1, "!= Expected", ret1Exp)
}
if *ret2 != ret2Exp {
t.Error("int result", *ret2, "!= Expected", ret2Exp)
}
}
func TestUnmarshal(t *testing.T) {
const definition = `[
{ "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
{ "name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] },
{ "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
{ "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
{ "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
{ "name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] },
{ "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] },
{ "name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] },
{ "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]`
abi, err := JSON(strings.NewReader(definition))
if err != nil {
t.Fatal(err)
}
buff := new(bytes.Buffer)
// marshall mixed bytes (mixedBytes)
p0, p0Exp := []byte{}, common.Hex2Bytes("01020000000000000000")
p1, p1Exp := [32]byte{}, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000ddeeff")
mixedBytes := []interface{}{&p0, &p1}
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000ddeeff"))
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000a"))
buff.Write(common.Hex2Bytes("0102000000000000000000000000000000000000000000000000000000000000"))
err = abi.Unpack(&mixedBytes, "mixedBytes", buff.Bytes())
if err != nil {
t.Error(err)
} else {
if !bytes.Equal(p0, p0Exp) {
t.Errorf("unexpected value unpacked: want %x, got %x", p0Exp, p0)
}
if !bytes.Equal(p1[:], p1Exp) {
t.Errorf("unexpected value unpacked: want %x, got %x", p1Exp, p1)
}
}
// marshal int
var Int *big.Int
err = abi.Unpack(&Int, "int", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
if err != nil {
t.Error(err)
}
if Int == nil || Int.Cmp(big.NewInt(1)) != 0 {
t.Error("expected Int to be 1 got", Int)
}
// marshal bool
var Bool bool
err = abi.Unpack(&Bool, "bool", common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
if err != nil {
t.Error(err)
}
if !Bool {
t.Error("expected Bool to be true")
}
// marshal dynamic bytes max length 32
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
bytesOut := common.RightPadBytes([]byte("hello"), 32)
buff.Write(bytesOut)
var Bytes []byte
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
if err != nil {
t.Error(err)
}
if !bytes.Equal(Bytes, bytesOut) {
t.Errorf("expected %x got %x", bytesOut, Bytes)
}
// marshall dynamic bytes max length 64
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040"))
bytesOut = common.RightPadBytes([]byte("hello"), 64)
buff.Write(bytesOut)
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
if err != nil {
t.Error(err)
}
if !bytes.Equal(Bytes, bytesOut) {
t.Errorf("expected %x got %x", bytesOut, Bytes)
}
// marshall dynamic bytes max length 64
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000003f"))
bytesOut = common.RightPadBytes([]byte("hello"), 64)
buff.Write(bytesOut)
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
if err != nil {
t.Error(err)
}
if !bytes.Equal(Bytes, bytesOut[:len(bytesOut)-1]) {
t.Errorf("expected %x got %x", bytesOut[:len(bytesOut)-1], Bytes)
}
// marshal dynamic bytes output empty
err = abi.Unpack(&Bytes, "bytes", nil)
if err == nil {
t.Error("expected error")
}
// marshal dynamic bytes length 5
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000005"))
buff.Write(common.RightPadBytes([]byte("hello"), 32))
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
if err != nil {
t.Error(err)
}
if !bytes.Equal(Bytes, []byte("hello")) {
t.Errorf("expected %x got %x", bytesOut, Bytes)
}
// marshal dynamic bytes length 5
buff.Reset()
buff.Write(common.RightPadBytes([]byte("hello"), 32))
var hash common.Hash
err = abi.Unpack(&hash, "fixed", buff.Bytes())
if err != nil {
t.Error(err)
}
helloHash := common.BytesToHash(common.RightPadBytes([]byte("hello"), 32))
if hash != helloHash {
t.Errorf("Expected %x to equal %x", hash, helloHash)
}
// marshal error
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020"))
err = abi.Unpack(&Bytes, "bytes", buff.Bytes())
if err == nil {
t.Error("expected error")
}
err = abi.Unpack(&Bytes, "multi", make([]byte, 64))
if err == nil {
t.Error("expected error")
}
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003"))
// marshal int array
var intArray [3]*big.Int
err = abi.Unpack(&intArray, "intArraySingle", buff.Bytes())
if err != nil {
t.Error(err)
}
var testAgainstIntArray [3]*big.Int
testAgainstIntArray[0] = big.NewInt(1)
testAgainstIntArray[1] = big.NewInt(2)
testAgainstIntArray[2] = big.NewInt(3)
for i, Int := range intArray {
if Int.Cmp(testAgainstIntArray[i]) != 0 {
t.Errorf("expected %v, got %v", testAgainstIntArray[i], Int)
}
}
// marshal address slice
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) // offset
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // size
buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000"))
var outAddr []common.Address
err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes())
if err != nil {
t.Fatal("didn't expect error:", err)
}
if len(outAddr) != 1 {
t.Fatal("expected 1 item, got", len(outAddr))
}
if outAddr[0] != (common.Address{1}) {
t.Errorf("expected %x, got %x", common.Address{1}, outAddr[0])
}
// marshal multiple address slice
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) // offset
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000080")) // offset
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // size
buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000"))
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // size
buff.Write(common.Hex2Bytes("0000000000000000000000000200000000000000000000000000000000000000"))
buff.Write(common.Hex2Bytes("0000000000000000000000000300000000000000000000000000000000000000"))
var outAddrStruct struct {
A []common.Address
B []common.Address
}
err = abi.Unpack(&outAddrStruct, "addressSliceDouble", buff.Bytes())
if err != nil {
t.Fatal("didn't expect error:", err)
}
if len(outAddrStruct.A) != 1 {
t.Fatal("expected 1 item, got", len(outAddrStruct.A))
}
if outAddrStruct.A[0] != (common.Address{1}) {
t.Errorf("expected %x, got %x", common.Address{1}, outAddrStruct.A[0])
}
if len(outAddrStruct.B) != 2 {
t.Fatal("expected 1 item, got", len(outAddrStruct.B))
}
if outAddrStruct.B[0] != (common.Address{2}) {
t.Errorf("expected %x, got %x", common.Address{2}, outAddrStruct.B[0])
}
if outAddrStruct.B[1] != (common.Address{3}) {
t.Errorf("expected %x, got %x", common.Address{3}, outAddrStruct.B[1])
}
// marshal invalid address slice
buff.Reset()
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000100"))
err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes())
if err == nil {
t.Fatal("expected error:", err)
}
}
func TestOOMMaliciousInput(t *testing.T) {
oomTests := []unpackTest{
{
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
"0000000000000000000000000000000000000000000000000000000000000003" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Length larger than 64 bits
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
"00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Offset very large (over 64 bits)
def: `[{"type": "uint8[]"}]`,
enc: "00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000020" + // offset
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Offset very large (below 64 bits)
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000007ffffffffff00020" + // offset
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Offset negative (as 64 bit)
def: `[{"type": "uint8[]"}]`,
enc: "000000000000000000000000000000000000000000000000f000000000000020" + // offset
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Negative length
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
"000000000000000000000000000000000000000000000000f000000000000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
{ // Very large length
def: `[{"type": "uint8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
"0000000000000000000000000000000000000000000000007fffffffff000002" + // num elems
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
},
}
for i, test := range oomTests {
def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
abi, err := JSON(strings.NewReader(def))
if err != nil {
t.Fatalf("invalid ABI definition %s: %v", def, err)
}
encb, err := hex.DecodeString(test.enc)
if err != nil {
t.Fatalf("invalid hex: %s" + test.enc)
}
_, err = abi.Methods["method"].Outputs.UnpackValues(encb)
if err == nil {
t.Fatalf("Expected error on malicious input, test %d", i)
}
}
}

View File

@@ -1,363 +0,0 @@
// 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 accounts implements encrypted storage of secp256k1 private keys.
//
// Keys are stored as encrypted JSON files according to the Web3 Secret Storage specification.
// See https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition for more information.
package accounts
import (
"crypto/ecdsa"
crand "crypto/rand"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"sync"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
var (
ErrLocked = errors.New("account is locked")
ErrNoMatch = errors.New("no key for given address or file")
ErrDecrypt = errors.New("could not decrypt key with given passphrase")
)
// Account represents a stored key.
// When used as an argument, it selects a unique key file to act on.
type Account struct {
Address common.Address // Ethereum account address derived from the key
// File contains the key file name.
// When Acccount is used as an argument to select a key, File can be left blank to
// select just by address or set to the basename or absolute path of a file in the key
// directory. Accounts returned by Manager will always contain an absolute path.
File string
}
func (acc *Account) MarshalJSON() ([]byte, error) {
return []byte(`"` + acc.Address.Hex() + `"`), nil
}
func (acc *Account) UnmarshalJSON(raw []byte) error {
return json.Unmarshal(raw, &acc.Address)
}
// Manager manages a key storage directory on disk.
type Manager struct {
cache *addrCache
keyStore keyStore
mu sync.RWMutex
unlocked map[common.Address]*unlocked
}
type unlocked struct {
*Key
abort chan struct{}
}
// NewManager creates a manager for the given directory.
func NewManager(keydir string, scryptN, scryptP int) *Manager {
keydir, _ = filepath.Abs(keydir)
am := &Manager{keyStore: &keyStorePassphrase{keydir, scryptN, scryptP}}
am.init(keydir)
return am
}
// NewPlaintextManager creates a manager for the given directory.
// Deprecated: Use NewManager.
func NewPlaintextManager(keydir string) *Manager {
keydir, _ = filepath.Abs(keydir)
am := &Manager{keyStore: &keyStorePlain{keydir}}
am.init(keydir)
return am
}
func (am *Manager) init(keydir string) {
am.unlocked = make(map[common.Address]*unlocked)
am.cache = newAddrCache(keydir)
// TODO: In order for this finalizer to work, there must be no references
// to am. addrCache doesn't keep a reference but unlocked keys do,
// so the finalizer will not trigger until all timed unlocks have expired.
runtime.SetFinalizer(am, func(m *Manager) {
m.cache.close()
})
}
// HasAddress reports whether a key with the given address is present.
func (am *Manager) HasAddress(addr common.Address) bool {
return am.cache.hasAddress(addr)
}
// Accounts returns all key files present in the directory.
func (am *Manager) Accounts() []Account {
return am.cache.accounts()
}
// DeleteAccount deletes the key matched by account if the passphrase is correct.
// If a contains no filename, the address must match a unique key.
func (am *Manager) DeleteAccount(a Account, passphrase string) error {
// Decrypting the key isn't really necessary, but we do
// it anyway to check the password and zero out the key
// immediately afterwards.
a, key, err := am.getDecryptedKey(a, passphrase)
if key != nil {
zeroKey(key.PrivateKey)
}
if err != nil {
return err
}
// The order is crucial here. The key is dropped from the
// cache after the file is gone so that a reload happening in
// between won't insert it into the cache again.
err = os.Remove(a.File)
if err == nil {
am.cache.delete(a)
}
return err
}
// Sign calculates a ECDSA signature for the given hash.
// Note, Ethereum signatures have a particular format as described in the
// yellow paper. Use the SignEthereum function to calculate a signature
// in Ethereum format.
func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
am.mu.RLock()
defer am.mu.RUnlock()
unlockedKey, found := am.unlocked[addr]
if !found {
return nil, ErrLocked
}
return crypto.Sign(hash, unlockedKey.PrivateKey)
}
// SignEthereum calculates a ECDSA signature for the given hash.
// The signature has the format as described in the Ethereum yellow paper.
func (am *Manager) SignEthereum(addr common.Address, hash []byte) ([]byte, error) {
am.mu.RLock()
defer am.mu.RUnlock()
unlockedKey, found := am.unlocked[addr]
if !found {
return nil, ErrLocked
}
return crypto.SignEthereum(hash, unlockedKey.PrivateKey)
}
// SignWithPassphrase signs hash if the private key matching the given
// address can be decrypted with the given passphrase.
func (am *Manager) SignWithPassphrase(addr common.Address, passphrase string, hash []byte) (signature []byte, err error) {
_, key, err := am.getDecryptedKey(Account{Address: addr}, passphrase)
if err != nil {
return nil, err
}
defer zeroKey(key.PrivateKey)
return crypto.SignEthereum(hash, key.PrivateKey)
}
// Unlock unlocks the given account indefinitely.
func (am *Manager) Unlock(a Account, passphrase string) error {
return am.TimedUnlock(a, passphrase, 0)
}
// Lock removes the private key with the given address from memory.
func (am *Manager) Lock(addr common.Address) error {
am.mu.Lock()
if unl, found := am.unlocked[addr]; found {
am.mu.Unlock()
am.expire(addr, unl, time.Duration(0)*time.Nanosecond)
} else {
am.mu.Unlock()
}
return nil
}
// TimedUnlock unlocks the given account with the passphrase. The account
// stays unlocked for the duration of timeout. A timeout of 0 unlocks the account
// until the program exits. The account must match a unique key file.
//
// If the account address is already unlocked for a duration, TimedUnlock extends or
// shortens the active unlock timeout. If the address was previously unlocked
// indefinitely the timeout is not altered.
func (am *Manager) TimedUnlock(a Account, passphrase string, timeout time.Duration) error {
a, key, err := am.getDecryptedKey(a, passphrase)
if err != nil {
return err
}
am.mu.Lock()
defer am.mu.Unlock()
u, found := am.unlocked[a.Address]
if found {
if u.abort == nil {
// The address was unlocked indefinitely, so unlocking
// it with a timeout would be confusing.
zeroKey(key.PrivateKey)
return nil
} else {
// Terminate the expire goroutine and replace it below.
close(u.abort)
}
}
if timeout > 0 {
u = &unlocked{Key: key, abort: make(chan struct{})}
go am.expire(a.Address, u, timeout)
} else {
u = &unlocked{Key: key}
}
am.unlocked[a.Address] = u
return nil
}
// Find resolves the given account into a unique entry in the keystore.
func (am *Manager) Find(a Account) (Account, error) {
am.cache.maybeReload()
am.cache.mu.Lock()
a, err := am.cache.find(a)
am.cache.mu.Unlock()
return a, err
}
func (am *Manager) getDecryptedKey(a Account, auth string) (Account, *Key, error) {
a, err := am.Find(a)
if err != nil {
return a, nil, err
}
key, err := am.keyStore.GetKey(a.Address, a.File, auth)
return a, key, err
}
func (am *Manager) expire(addr common.Address, u *unlocked, timeout time.Duration) {
t := time.NewTimer(timeout)
defer t.Stop()
select {
case <-u.abort:
// just quit
case <-t.C:
am.mu.Lock()
// only drop if it's still the same key instance that dropLater
// was launched with. we can check that using pointer equality
// because the map stores a new pointer every time the key is
// unlocked.
if am.unlocked[addr] == u {
zeroKey(u.PrivateKey)
delete(am.unlocked, addr)
}
am.mu.Unlock()
}
}
// NewAccount generates a new key and stores it into the key directory,
// encrypting it with the passphrase.
func (am *Manager) NewAccount(passphrase string) (Account, error) {
_, account, err := storeNewKey(am.keyStore, crand.Reader, passphrase)
if err != nil {
return Account{}, err
}
// Add the account to the cache immediately rather
// than waiting for file system notifications to pick it up.
am.cache.add(account)
return account, nil
}
// AccountByIndex returns the ith account.
func (am *Manager) AccountByIndex(i int) (Account, error) {
accounts := am.Accounts()
if i < 0 || i >= len(accounts) {
return Account{}, fmt.Errorf("account index %d out of range [0, %d]", i, len(accounts)-1)
}
return accounts[i], nil
}
// Export exports as a JSON key, encrypted with newPassphrase.
func (am *Manager) Export(a Account, passphrase, newPassphrase string) (keyJSON []byte, err error) {
_, key, err := am.getDecryptedKey(a, passphrase)
if err != nil {
return nil, err
}
var N, P int
if store, ok := am.keyStore.(*keyStorePassphrase); ok {
N, P = store.scryptN, store.scryptP
} else {
N, P = StandardScryptN, StandardScryptP
}
return EncryptKey(key, newPassphrase, N, P)
}
// Import stores the given encrypted JSON key into the key directory.
func (am *Manager) Import(keyJSON []byte, passphrase, newPassphrase string) (Account, error) {
key, err := DecryptKey(keyJSON, passphrase)
if key != nil && key.PrivateKey != nil {
defer zeroKey(key.PrivateKey)
}
if err != nil {
return Account{}, err
}
return am.importKey(key, newPassphrase)
}
// ImportECDSA stores the given key into the key directory, encrypting it with the passphrase.
func (am *Manager) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (Account, error) {
key := newKeyFromECDSA(priv)
if am.cache.hasAddress(key.Address) {
return Account{}, fmt.Errorf("account already exists")
}
return am.importKey(key, passphrase)
}
func (am *Manager) importKey(key *Key, passphrase string) (Account, error) {
a := Account{Address: key.Address, File: am.keyStore.JoinPath(keyFileName(key.Address))}
if err := am.keyStore.StoreKey(a.File, key, passphrase); err != nil {
return Account{}, err
}
am.cache.add(a)
return a, nil
}
// Update changes the passphrase of an existing account.
func (am *Manager) Update(a Account, passphrase, newPassphrase string) error {
a, key, err := am.getDecryptedKey(a, passphrase)
if err != nil {
return err
}
return am.keyStore.StoreKey(a.File, key, newPassphrase)
}
// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores
// a key file in the key directory. The key file is encrypted with the same passphrase.
func (am *Manager) ImportPreSaleKey(keyJSON []byte, passphrase string) (Account, error) {
a, _, err := importPreSaleKey(am.keyStore, keyJSON, passphrase)
if err != nil {
return a, err
}
am.cache.add(a)
return a, nil
}
// zeroKey zeroes a private key in memory.
func zeroKey(k *ecdsa.PrivateKey) {
b := k.D.Bits()
for i := range b {
b[i] = 0
}
}

173
accounts/accounts.go Normal file
View File

@@ -0,0 +1,173 @@
// Copyright 2017 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 accounts implements high level Ethereum account management.
package accounts
import (
"math/big"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// Account represents an Ethereum account located at a specific location defined
// by the optional URL field.
type Account struct {
Address common.Address `json:"address"` // Ethereum account address derived from the key
URL URL `json:"url"` // Optional resource locator within a backend
}
// Wallet represents a software or hardware wallet that might contain one or more
// accounts (derived from the same seed).
type Wallet interface {
// URL retrieves the canonical path under which this wallet is reachable. It is
// user by upper layers to define a sorting order over all wallets from multiple
// backends.
URL() URL
// Status returns a textual status to aid the user in the current state of the
// wallet. It also returns an error indicating any failure the wallet might have
// encountered.
Status() (string, error)
// Open initializes access to a wallet instance. It is not meant to unlock or
// decrypt account keys, rather simply to establish a connection to hardware
// wallets and/or to access derivation seeds.
//
// The passphrase parameter may or may not be used by the implementation of a
// particular wallet instance. The reason there is no passwordless open method
// is to strive towards a uniform wallet handling, oblivious to the different
// backend providers.
//
// Please note, if you open a wallet, you must close it to release any allocated
// resources (especially important when working with hardware wallets).
Open(passphrase string) error
// Close releases any resources held by an open wallet instance.
Close() error
// Accounts retrieves the list of signing accounts the wallet is currently aware
// of. For hierarchical deterministic wallets, the list will not be exhaustive,
// rather only contain the accounts explicitly pinned during account derivation.
Accounts() []Account
// Contains returns whether an account is part of this particular wallet or not.
Contains(account Account) bool
// Derive attempts to explicitly derive a hierarchical deterministic account at
// the specified derivation path. If requested, the derived account will be added
// to the wallet's tracked account list.
Derive(path DerivationPath, pin bool) (Account, error)
// SelfDerive sets a base account derivation path from which the wallet attempts
// to discover non zero accounts and automatically add them to list of tracked
// accounts.
//
// Note, self derivaton will increment the last component of the specified path
// opposed to decending into a child path to allow discovering accounts starting
// from non zero components.
//
// You can disable automatic account discovery by calling SelfDerive with a nil
// chain state reader.
SelfDerive(base DerivationPath, chain ethereum.ChainStateReader)
// SignHash requests the wallet to sign the given hash.
//
// It looks up the account specified either solely via its address contained within,
// or optionally with the aid of any location metadata from the embedded URL field.
//
// If the wallet requires additional authentication to sign the request (e.g.
// a password to decrypt the account, or a PIN code o verify the transaction),
// an AuthNeededError instance will be returned, containing infos for the user
// about which fields or actions are needed. The user may retry by providing
// the needed details via SignHashWithPassphrase, or by other means (e.g. unlock
// the account in a keystore).
SignHash(account Account, hash []byte) ([]byte, error)
// SignTx requests the wallet to sign the given transaction.
//
// It looks up the account specified either solely via its address contained within,
// or optionally with the aid of any location metadata from the embedded URL field.
//
// If the wallet requires additional authentication to sign the request (e.g.
// a password to decrypt the account, or a PIN code o verify the transaction),
// an AuthNeededError instance will be returned, containing infos for the user
// about which fields or actions are needed. The user may retry by providing
// the needed details via SignTxWithPassphrase, or by other means (e.g. unlock
// the account in a keystore).
SignTx(account Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
// SignHashWithPassphrase requests the wallet to sign the given hash with the
// given passphrase as extra authentication information.
//
// It looks up the account specified either solely via its address contained within,
// or optionally with the aid of any location metadata from the embedded URL field.
SignHashWithPassphrase(account Account, passphrase string, hash []byte) ([]byte, error)
// SignTxWithPassphrase requests the wallet to sign the given transaction, with the
// given passphrase as extra authentication information.
//
// It looks up the account specified either solely via its address contained within,
// or optionally with the aid of any location metadata from the embedded URL field.
SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
}
// Backend is a "wallet provider" that may contain a batch of accounts they can
// sign transactions with and upon request, do so.
type Backend interface {
// Wallets retrieves the list of wallets the backend is currently aware of.
//
// The returned wallets are not opened by default. For software HD wallets this
// means that no base seeds are decrypted, and for hardware wallets that no actual
// connection is established.
//
// The resulting wallet list will be sorted alphabetically based on its internal
// URL assigned by the backend. Since wallets (especially hardware) may come and
// go, the same wallet might appear at a different positions in the list during
// subsequent retrievals.
Wallets() []Wallet
// Subscribe creates an async subscription to receive notifications when the
// backend detects the arrival or departure of a wallet.
Subscribe(sink chan<- WalletEvent) event.Subscription
}
// WalletEventType represents the different event types that can be fired by
// the wallet subscription subsystem.
type WalletEventType int
const (
// WalletArrived is fired when a new wallet is detected either via USB or via
// a filesystem event in the keystore.
WalletArrived WalletEventType = iota
// WalletOpened is fired when a wallet is successfully opened with the purpose
// of starting any background processes such as automatic key derivation.
WalletOpened
// WalletDropped
WalletDropped
)
// WalletEvent is an event fired by an account backend when a wallet arrival or
// departure is detected.
type WalletEvent struct {
Wallet Wallet // Wallet instance arrived or departed
Kind WalletEventType // Event type that happened in the system
}

View File

@@ -1,218 +0,0 @@
// 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 accounts
import (
"io/ioutil"
"os"
"runtime"
"strings"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
)
var testSigData = make([]byte, 32)
func TestManager(t *testing.T) {
dir, am := tmpManager(t, true)
defer os.RemoveAll(dir)
a, err := am.NewAccount("foo")
if err != nil {
t.Fatal(err)
}
if !strings.HasPrefix(a.File, dir) {
t.Errorf("account file %s doesn't have dir prefix", a.File)
}
stat, err := os.Stat(a.File)
if err != nil {
t.Fatalf("account file %s doesn't exist (%v)", a.File, err)
}
if runtime.GOOS != "windows" && stat.Mode() != 0600 {
t.Fatalf("account file has wrong mode: got %o, want %o", stat.Mode(), 0600)
}
if !am.HasAddress(a.Address) {
t.Errorf("HasAccount(%x) should've returned true", a.Address)
}
if err := am.Update(a, "foo", "bar"); err != nil {
t.Errorf("Update error: %v", err)
}
if err := am.DeleteAccount(a, "bar"); err != nil {
t.Errorf("DeleteAccount error: %v", err)
}
if common.FileExist(a.File) {
t.Errorf("account file %s should be gone after DeleteAccount", a.File)
}
if am.HasAddress(a.Address) {
t.Errorf("HasAccount(%x) should've returned true after DeleteAccount", a.Address)
}
}
func TestSign(t *testing.T) {
dir, am := tmpManager(t, true)
defer os.RemoveAll(dir)
pass := "" // not used but required by API
a1, err := am.NewAccount(pass)
if err != nil {
t.Fatal(err)
}
if err := am.Unlock(a1, ""); err != nil {
t.Fatal(err)
}
if _, err := am.Sign(a1.Address, testSigData); err != nil {
t.Fatal(err)
}
}
func TestSignWithPassphrase(t *testing.T) {
dir, am := tmpManager(t, true)
defer os.RemoveAll(dir)
pass := "passwd"
acc, err := am.NewAccount(pass)
if err != nil {
t.Fatal(err)
}
if _, unlocked := am.unlocked[acc.Address]; unlocked {
t.Fatal("expected account to be locked")
}
_, err = am.SignWithPassphrase(acc.Address, pass, testSigData)
if err != nil {
t.Fatal(err)
}
if _, unlocked := am.unlocked[acc.Address]; unlocked {
t.Fatal("expected account to be locked")
}
if _, err = am.SignWithPassphrase(acc.Address, "invalid passwd", testSigData); err == nil {
t.Fatal("expected SignHash to fail with invalid password")
}
}
func TestTimedUnlock(t *testing.T) {
dir, am := tmpManager(t, true)
defer os.RemoveAll(dir)
pass := "foo"
a1, err := am.NewAccount(pass)
// Signing without passphrase fails because account is locked
_, err = am.Sign(a1.Address, testSigData)
if err != ErrLocked {
t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err)
}
// Signing with passphrase works
if err = am.TimedUnlock(a1, pass, 100*time.Millisecond); err != nil {
t.Fatal(err)
}
// Signing without passphrase works because account is temp unlocked
_, err = am.Sign(a1.Address, testSigData)
if err != nil {
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
}
// Signing fails again after automatic locking
time.Sleep(250 * time.Millisecond)
_, err = am.Sign(a1.Address, testSigData)
if err != ErrLocked {
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
}
}
func TestOverrideUnlock(t *testing.T) {
dir, am := tmpManager(t, false)
defer os.RemoveAll(dir)
pass := "foo"
a1, err := am.NewAccount(pass)
// Unlock indefinitely.
if err = am.TimedUnlock(a1, pass, 5*time.Minute); err != nil {
t.Fatal(err)
}
// Signing without passphrase works because account is temp unlocked
_, err = am.Sign(a1.Address, testSigData)
if err != nil {
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
}
// reset unlock to a shorter period, invalidates the previous unlock
if err = am.TimedUnlock(a1, pass, 100*time.Millisecond); err != nil {
t.Fatal(err)
}
// Signing without passphrase still works because account is temp unlocked
_, err = am.Sign(a1.Address, testSigData)
if err != nil {
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
}
// Signing fails again after automatic locking
time.Sleep(250 * time.Millisecond)
_, err = am.Sign(a1.Address, testSigData)
if err != ErrLocked {
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
}
}
// This test should fail under -race if signing races the expiration goroutine.
func TestSignRace(t *testing.T) {
dir, am := tmpManager(t, false)
defer os.RemoveAll(dir)
// Create a test account.
a1, err := am.NewAccount("")
if err != nil {
t.Fatal("could not create the test account", err)
}
if err := am.TimedUnlock(a1, "", 15*time.Millisecond); err != nil {
t.Fatal("could not unlock the test account", err)
}
end := time.Now().Add(500 * time.Millisecond)
for time.Now().Before(end) {
if _, err := am.Sign(a1.Address, testSigData); err == ErrLocked {
return
} else if err != nil {
t.Errorf("Sign error: %v", err)
return
}
time.Sleep(1 * time.Millisecond)
}
t.Errorf("Account did not lock within the timeout")
}
func tmpManager(t *testing.T, encrypted bool) (string, *Manager) {
d, err := ioutil.TempDir("", "eth-keystore-test")
if err != nil {
t.Fatal(err)
}
new := NewPlaintextManager
if encrypted {
new = func(kd string) *Manager { return NewManager(kd, veryLightScryptN, veryLightScryptP) }
}
return d, new(d)
}

View File

@@ -1,269 +0,0 @@
// Copyright 2016 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 accounts
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
)
// Minimum amount of time between cache reloads. This limit applies if the platform does
// not support change notifications. It also applies if the keystore directory does not
// exist yet, the code will attempt to create a watcher at most this often.
const minReloadInterval = 2 * time.Second
type accountsByFile []Account
func (s accountsByFile) Len() int { return len(s) }
func (s accountsByFile) Less(i, j int) bool { return s[i].File < s[j].File }
func (s accountsByFile) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// AmbiguousAddrError is returned when attempting to unlock
// an address for which more than one file exists.
type AmbiguousAddrError struct {
Addr common.Address
Matches []Account
}
func (err *AmbiguousAddrError) Error() string {
files := ""
for i, a := range err.Matches {
files += a.File
if i < len(err.Matches)-1 {
files += ", "
}
}
return fmt.Sprintf("multiple keys match address (%s)", files)
}
// addrCache is a live index of all accounts in the keystore.
type addrCache struct {
keydir string
watcher *watcher
mu sync.Mutex
all accountsByFile
byAddr map[common.Address][]Account
throttle *time.Timer
}
func newAddrCache(keydir string) *addrCache {
ac := &addrCache{
keydir: keydir,
byAddr: make(map[common.Address][]Account),
}
ac.watcher = newWatcher(ac)
return ac
}
func (ac *addrCache) accounts() []Account {
ac.maybeReload()
ac.mu.Lock()
defer ac.mu.Unlock()
cpy := make([]Account, len(ac.all))
copy(cpy, ac.all)
return cpy
}
func (ac *addrCache) hasAddress(addr common.Address) bool {
ac.maybeReload()
ac.mu.Lock()
defer ac.mu.Unlock()
return len(ac.byAddr[addr]) > 0
}
func (ac *addrCache) add(newAccount Account) {
ac.mu.Lock()
defer ac.mu.Unlock()
i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].File >= newAccount.File })
if i < len(ac.all) && ac.all[i] == newAccount {
return
}
// newAccount is not in the cache.
ac.all = append(ac.all, Account{})
copy(ac.all[i+1:], ac.all[i:])
ac.all[i] = newAccount
ac.byAddr[newAccount.Address] = append(ac.byAddr[newAccount.Address], newAccount)
}
// note: removed needs to be unique here (i.e. both File and Address must be set).
func (ac *addrCache) delete(removed Account) {
ac.mu.Lock()
defer ac.mu.Unlock()
ac.all = removeAccount(ac.all, removed)
if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 {
delete(ac.byAddr, removed.Address)
} else {
ac.byAddr[removed.Address] = ba
}
}
func removeAccount(slice []Account, elem Account) []Account {
for i := range slice {
if slice[i] == elem {
return append(slice[:i], slice[i+1:]...)
}
}
return slice
}
// find returns the cached account for address if there is a unique match.
// The exact matching rules are explained by the documentation of Account.
// Callers must hold ac.mu.
func (ac *addrCache) find(a Account) (Account, error) {
// Limit search to address candidates if possible.
matches := ac.all
if (a.Address != common.Address{}) {
matches = ac.byAddr[a.Address]
}
if a.File != "" {
// If only the basename is specified, complete the path.
if !strings.ContainsRune(a.File, filepath.Separator) {
a.File = filepath.Join(ac.keydir, a.File)
}
for i := range matches {
if matches[i].File == a.File {
return matches[i], nil
}
}
if (a.Address == common.Address{}) {
return Account{}, ErrNoMatch
}
}
switch len(matches) {
case 1:
return matches[0], nil
case 0:
return Account{}, ErrNoMatch
default:
err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]Account, len(matches))}
copy(err.Matches, matches)
return Account{}, err
}
}
func (ac *addrCache) maybeReload() {
ac.mu.Lock()
defer ac.mu.Unlock()
if ac.watcher.running {
return // A watcher is running and will keep the cache up-to-date.
}
if ac.throttle == nil {
ac.throttle = time.NewTimer(0)
} else {
select {
case <-ac.throttle.C:
default:
return // The cache was reloaded recently.
}
}
ac.watcher.start()
ac.reload()
ac.throttle.Reset(minReloadInterval)
}
func (ac *addrCache) close() {
ac.mu.Lock()
ac.watcher.close()
if ac.throttle != nil {
ac.throttle.Stop()
}
ac.mu.Unlock()
}
// reload caches addresses of existing accounts.
// Callers must hold ac.mu.
func (ac *addrCache) reload() {
accounts, err := ac.scan()
if err != nil && glog.V(logger.Debug) {
glog.Errorf("can't load keys: %v", err)
}
ac.all = accounts
sort.Sort(ac.all)
for k := range ac.byAddr {
delete(ac.byAddr, k)
}
for _, a := range accounts {
ac.byAddr[a.Address] = append(ac.byAddr[a.Address], a)
}
glog.V(logger.Debug).Infof("reloaded keys, cache has %d accounts", len(ac.all))
}
func (ac *addrCache) scan() ([]Account, error) {
files, err := ioutil.ReadDir(ac.keydir)
if err != nil {
return nil, err
}
var (
buf = new(bufio.Reader)
addrs []Account
keyJSON struct {
Address common.Address `json:"address"`
}
)
for _, fi := range files {
path := filepath.Join(ac.keydir, fi.Name())
if skipKeyFile(fi) {
glog.V(logger.Detail).Infof("ignoring file %s", path)
continue
}
fd, err := os.Open(path)
if err != nil {
glog.V(logger.Detail).Infoln(err)
continue
}
buf.Reset(fd)
// Parse the address.
keyJSON.Address = common.Address{}
err = json.NewDecoder(buf).Decode(&keyJSON)
switch {
case err != nil:
glog.V(logger.Debug).Infof("can't decode key %s: %v", path, err)
case (keyJSON.Address == common.Address{}):
glog.V(logger.Debug).Infof("can't decode key %s: missing or zero address", path)
default:
addrs = append(addrs, Account{Address: keyJSON.Address, File: path})
}
fd.Close()
}
return addrs, err
}
func skipKeyFile(fi os.FileInfo) bool {
// Skip editor backups and UNIX-style hidden files.
if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") {
return true
}
// Skip misc special files, directories (yes, symlinks too).
if fi.IsDir() || fi.Mode()&os.ModeType != 0 {
return true
}
return false
}

View File

@@ -1,283 +0,0 @@
// Copyright 2016 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 accounts
import (
"fmt"
"math/rand"
"os"
"path/filepath"
"reflect"
"sort"
"testing"
"time"
"github.com/cespare/cp"
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common"
)
var (
cachetestDir, _ = filepath.Abs(filepath.Join("testdata", "keystore"))
cachetestAccounts = []Account{
{
Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
File: filepath.Join(cachetestDir, "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
},
{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
File: filepath.Join(cachetestDir, "aaa"),
},
{
Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
File: filepath.Join(cachetestDir, "zzz"),
},
}
)
func TestWatchNewFile(t *testing.T) {
t.Parallel()
dir, am := tmpManager(t, false)
defer os.RemoveAll(dir)
// Ensure the watcher is started before adding any files.
am.Accounts()
time.Sleep(200 * time.Millisecond)
// Move in the files.
wantAccounts := make([]Account, len(cachetestAccounts))
for i := range cachetestAccounts {
a := cachetestAccounts[i]
a.File = filepath.Join(dir, filepath.Base(a.File))
wantAccounts[i] = a
if err := cp.CopyFile(a.File, cachetestAccounts[i].File); err != nil {
t.Fatal(err)
}
}
// am should see the accounts.
var list []Account
for d := 200 * time.Millisecond; d < 5*time.Second; d *= 2 {
list = am.Accounts()
if reflect.DeepEqual(list, wantAccounts) {
return
}
time.Sleep(d)
}
t.Errorf("got %s, want %s", spew.Sdump(list), spew.Sdump(wantAccounts))
}
func TestWatchNoDir(t *testing.T) {
t.Parallel()
// Create am but not the directory that it watches.
rand.Seed(time.Now().UnixNano())
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watch-test-%d-%d", os.Getpid(), rand.Int()))
am := NewManager(dir, LightScryptN, LightScryptP)
list := am.Accounts()
if len(list) > 0 {
t.Error("initial account list not empty:", list)
}
time.Sleep(100 * time.Millisecond)
// Create the directory and copy a key file into it.
os.MkdirAll(dir, 0700)
defer os.RemoveAll(dir)
file := filepath.Join(dir, "aaa")
if err := cp.CopyFile(file, cachetestAccounts[0].File); err != nil {
t.Fatal(err)
}
// am should see the account.
wantAccounts := []Account{cachetestAccounts[0]}
wantAccounts[0].File = file
for d := 200 * time.Millisecond; d < 8*time.Second; d *= 2 {
list = am.Accounts()
if reflect.DeepEqual(list, wantAccounts) {
return
}
time.Sleep(d)
}
t.Errorf("\ngot %v\nwant %v", list, wantAccounts)
}
func TestCacheInitialReload(t *testing.T) {
cache := newAddrCache(cachetestDir)
accounts := cache.accounts()
if !reflect.DeepEqual(accounts, cachetestAccounts) {
t.Fatalf("got initial accounts: %swant %s", spew.Sdump(accounts), spew.Sdump(cachetestAccounts))
}
}
func TestCacheAddDeleteOrder(t *testing.T) {
cache := newAddrCache("testdata/no-such-dir")
cache.watcher.running = true // prevent unexpected reloads
accounts := []Account{
{
Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
File: "-309830980",
},
{
Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
File: "ggg",
},
{
Address: common.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"),
File: "zzzzzz-the-very-last-one.keyXXX",
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
File: "SOMETHING.key",
},
{
Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
File: "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
},
{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
File: "aaa",
},
{
Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
File: "zzz",
},
}
for _, a := range accounts {
cache.add(a)
}
// Add some of them twice to check that they don't get reinserted.
cache.add(accounts[0])
cache.add(accounts[2])
// Check that the account list is sorted by filename.
wantAccounts := make([]Account, len(accounts))
copy(wantAccounts, accounts)
sort.Sort(accountsByFile(wantAccounts))
list := cache.accounts()
if !reflect.DeepEqual(list, wantAccounts) {
t.Fatalf("got accounts: %s\nwant %s", spew.Sdump(accounts), spew.Sdump(wantAccounts))
}
for _, a := range accounts {
if !cache.hasAddress(a.Address) {
t.Errorf("expected hasAccount(%x) to return true", a.Address)
}
}
if cache.hasAddress(common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e")) {
t.Errorf("expected hasAccount(%x) to return false", common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"))
}
// Delete a few keys from the cache.
for i := 0; i < len(accounts); i += 2 {
cache.delete(wantAccounts[i])
}
cache.delete(Account{Address: common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"), File: "something"})
// Check content again after deletion.
wantAccountsAfterDelete := []Account{
wantAccounts[1],
wantAccounts[3],
wantAccounts[5],
}
list = cache.accounts()
if !reflect.DeepEqual(list, wantAccountsAfterDelete) {
t.Fatalf("got accounts after delete: %s\nwant %s", spew.Sdump(list), spew.Sdump(wantAccountsAfterDelete))
}
for _, a := range wantAccountsAfterDelete {
if !cache.hasAddress(a.Address) {
t.Errorf("expected hasAccount(%x) to return true", a.Address)
}
}
if cache.hasAddress(wantAccounts[0].Address) {
t.Errorf("expected hasAccount(%x) to return false", wantAccounts[0].Address)
}
}
func TestCacheFind(t *testing.T) {
dir := filepath.Join("testdata", "dir")
cache := newAddrCache(dir)
cache.watcher.running = true // prevent unexpected reloads
accounts := []Account{
{
Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
File: filepath.Join(dir, "a.key"),
},
{
Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
File: filepath.Join(dir, "b.key"),
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
File: filepath.Join(dir, "c.key"),
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
File: filepath.Join(dir, "c2.key"),
},
}
for _, a := range accounts {
cache.add(a)
}
nomatchAccount := Account{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
File: filepath.Join(dir, "something"),
}
tests := []struct {
Query Account
WantResult Account
WantError error
}{
// by address
{Query: Account{Address: accounts[0].Address}, WantResult: accounts[0]},
// by file
{Query: Account{File: accounts[0].File}, WantResult: accounts[0]},
// by basename
{Query: Account{File: filepath.Base(accounts[0].File)}, WantResult: accounts[0]},
// by file and address
{Query: accounts[0], WantResult: accounts[0]},
// ambiguous address, tie resolved by file
{Query: accounts[2], WantResult: accounts[2]},
// ambiguous address error
{
Query: Account{Address: accounts[2].Address},
WantError: &AmbiguousAddrError{
Addr: accounts[2].Address,
Matches: []Account{accounts[2], accounts[3]},
},
},
// no match error
{Query: nomatchAccount, WantError: ErrNoMatch},
{Query: Account{File: nomatchAccount.File}, WantError: ErrNoMatch},
{Query: Account{File: filepath.Base(nomatchAccount.File)}, WantError: ErrNoMatch},
{Query: Account{Address: nomatchAccount.Address}, WantError: ErrNoMatch},
}
for i, test := range tests {
a, err := cache.find(test.Query)
if !reflect.DeepEqual(err, test.WantError) {
t.Errorf("test %d: error mismatch for query %v\ngot %q\nwant %q", i, test.Query, err, test.WantError)
continue
}
if a != test.WantResult {
t.Errorf("test %d: result mismatch for query %v\ngot %v\nwant %v", i, test.Query, a, test.WantResult)
continue
}
}
}

68
accounts/errors.go Normal file
View File

@@ -0,0 +1,68 @@
// Copyright 2017 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 accounts
import (
"errors"
"fmt"
)
// ErrUnknownAccount is returned for any requested operation for which no backend
// provides the specified account.
var ErrUnknownAccount = errors.New("unknown account")
// ErrUnknownWallet is returned for any requested operation for which no backend
// provides the specified wallet.
var ErrUnknownWallet = errors.New("unknown wallet")
// ErrNotSupported is returned when an operation is requested from an account
// backend that it does not support.
var ErrNotSupported = errors.New("not supported")
// ErrInvalidPassphrase is returned when a decryption operation receives a bad
// passphrase.
var ErrInvalidPassphrase = errors.New("invalid passphrase")
// ErrWalletAlreadyOpen is returned if a wallet is attempted to be opened the
// second time.
var ErrWalletAlreadyOpen = errors.New("wallet already open")
// ErrWalletClosed is returned if a wallet is attempted to be opened the
// secodn time.
var ErrWalletClosed = errors.New("wallet closed")
// AuthNeededError is returned by backends for signing requests where the user
// is required to provide further authentication before signing can succeed.
//
// This usually means either that a password needs to be supplied, or perhaps a
// one time PIN code displayed by some hardware device.
type AuthNeededError struct {
Needed string // Extra authentication the user needs to provide
}
// NewAuthNeededError creates a new authentication error with the extra details
// about the needed fields set.
func NewAuthNeededError(needed string) error {
return &AuthNeededError{
Needed: needed,
}
}
// Error implements the standard error interface.
func (err *AuthNeededError) Error() string {
return fmt.Sprintf("authentication needed: %s", err.Needed)
}

135
accounts/hd.go Normal file
View File

@@ -0,0 +1,135 @@
// Copyright 2017 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 accounts
import (
"errors"
"fmt"
"math"
"math/big"
"strings"
)
// DefaultRootDerivationPath is the root path to which custom derivation endpoints
// are appended. As such, the first account will be at m/44'/60'/0'/0, the second
// at m/44'/60'/0'/1, etc.
var DefaultRootDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}
// DefaultBaseDerivationPath is the base path from which custom derivation endpoints
// are incremented. As such, the first account will be at m/44'/60'/0'/0, the second
// at m/44'/60'/0'/1, etc.
var DefaultBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0}
// DefaultLedgerBaseDerivationPath is the base path from which custom derivation endpoints
// are incremented. As such, the first account will be at m/44'/60'/0'/0, the second
// at m/44'/60'/0'/1, etc.
var DefaultLedgerBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}
// DerivationPath represents the computer friendly version of a hierarchical
// deterministic wallet account derivaion path.
//
// The BIP-32 spec https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
// defines derivation paths to be of the form:
//
// m / purpose' / coin_type' / account' / change / address_index
//
// The BIP-44 spec https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
// defines that the `purpose` be 44' (or 0x8000002C) for crypto currencies, and
// SLIP-44 https://github.com/satoshilabs/slips/blob/master/slip-0044.md assigns
// the `coin_type` 60' (or 0x8000003C) to Ethereum.
//
// The root path for Ethereum is m/44'/60'/0'/0 according to the specification
// from https://github.com/ethereum/EIPs/issues/84, albeit it's not set in stone
// yet whether accounts should increment the last component or the children of
// that. We will go with the simpler approach of incrementing the last component.
type DerivationPath []uint32
// ParseDerivationPath converts a user specified derivation path string to the
// internal binary representation.
//
// Full derivation paths need to start with the `m/` prefix, relative derivation
// paths (which will get appended to the default root path) must not have prefixes
// in front of the first element. Whitespace is ignored.
func ParseDerivationPath(path string) (DerivationPath, error) {
var result DerivationPath
// Handle absolute or relative paths
components := strings.Split(path, "/")
switch {
case len(components) == 0:
return nil, errors.New("empty derivation path")
case strings.TrimSpace(components[0]) == "":
return nil, errors.New("ambiguous path: use 'm/' prefix for absolute paths, or no leading '/' for relative ones")
case strings.TrimSpace(components[0]) == "m":
components = components[1:]
default:
result = append(result, DefaultRootDerivationPath...)
}
// All remaining components are relative, append one by one
if len(components) == 0 {
return nil, errors.New("empty derivation path") // Empty relative paths
}
for _, component := range components {
// Ignore any user added whitespace
component = strings.TrimSpace(component)
var value uint32
// Handle hardened paths
if strings.HasSuffix(component, "'") {
value = 0x80000000
component = strings.TrimSpace(strings.TrimSuffix(component, "'"))
}
// Handle the non hardened component
bigval, ok := new(big.Int).SetString(component, 0)
if !ok {
return nil, fmt.Errorf("invalid component: %s", component)
}
max := math.MaxUint32 - value
if bigval.Sign() < 0 || bigval.Cmp(big.NewInt(int64(max))) > 0 {
if value == 0 {
return nil, fmt.Errorf("component %v out of allowed range [0, %d]", bigval, max)
}
return nil, fmt.Errorf("component %v out of allowed hardened range [0, %d]", bigval, max)
}
value += uint32(bigval.Uint64())
// Append and repeat
result = append(result, value)
}
return result, nil
}
// String implements the stringer interface, converting a binary derivation path
// to its canonical representation.
func (path DerivationPath) String() string {
result := "m"
for _, component := range path {
var hardened bool
if component >= 0x80000000 {
component -= 0x80000000
hardened = true
}
result = fmt.Sprintf("%s/%d", result, component)
if hardened {
result += "'"
}
}
return result
}

79
accounts/hd_test.go Normal file
View File

@@ -0,0 +1,79 @@
// Copyright 2017 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 accounts
import (
"reflect"
"testing"
)
// Tests that HD derivation paths can be correctly parsed into our internal binary
// representation.
func TestHDPathParsing(t *testing.T) {
tests := []struct {
input string
output DerivationPath
}{
// Plain absolute derivation paths
{"m/44'/60'/0'/0", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}},
{"m/44'/60'/0'/128", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 128}},
{"m/44'/60'/0'/0'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}},
{"m/44'/60'/0'/128'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 128}},
{"m/2147483692/2147483708/2147483648/0", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}},
{"m/2147483692/2147483708/2147483648/2147483648", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}},
// Plain relative derivation paths
{"0", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0}},
{"128", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 128}},
{"0'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 0}},
{"128'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 128}},
{"2147483648", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 0}},
// Hexadecimal absolute derivation paths
{"m/0x2C'/0x3c'/0x00'/0x00", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}},
{"m/0x2C'/0x3c'/0x00'/0x80", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 128}},
{"m/0x2C'/0x3c'/0x00'/0x00'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}},
{"m/0x2C'/0x3c'/0x00'/0x80'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 128}},
{"m/0x8000002C/0x8000003c/0x80000000/0x00", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}},
{"m/0x8000002C/0x8000003c/0x80000000/0x80000000", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}},
// Hexadecimal relative derivation paths
{"0x00", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0}},
{"0x80", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 128}},
{"0x00'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 0}},
{"0x80'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 128}},
{"0x80000000", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 0}},
// Weird inputs just to ensure they work
{" m / 44 '\n/\n 60 \n\n\t' /\n0 ' /\t\t 0", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}},
// Invaid derivation paths
{"", nil}, // Empty relative derivation path
{"m", nil}, // Empty absolute derivation path
{"m/", nil}, // Missing last derivation component
{"/44'/60'/0'/0", nil}, // Absolute path without m prefix, might be user error
{"m/2147483648'", nil}, // Overflows 32 bit integer
{"m/-1'", nil}, // Cannot contain negative number
}
for i, tt := range tests {
if path, err := ParseDerivationPath(tt.input); !reflect.DeepEqual(path, tt.output) {
t.Errorf("test %d: parse mismatch: have %v (%v), want %v", i, path, err, tt.output)
} else if path == nil && err == nil {
t.Errorf("test %d: nil path and error: %v", i, err)
}
}
}

View File

@@ -1,305 +0,0 @@
// 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/>.
/*
This key store behaves as KeyStorePlain with the difference that
the private key is encrypted and on disk uses another JSON encoding.
The crypto is documented at https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
*/
package accounts
import (
"bytes"
"crypto/aes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/randentropy"
"github.com/pborman/uuid"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/scrypt"
)
const (
keyHeaderKDF = "scrypt"
// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
// memory and taking approximately 1s CPU time on a modern processor.
StandardScryptN = 1 << 18
// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
// memory and taking approximately 1s CPU time on a modern processor.
StandardScryptP = 1
// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
// memory and taking approximately 100ms CPU time on a modern processor.
LightScryptN = 1 << 12
// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
// memory and taking approximately 100ms CPU time on a modern processor.
LightScryptP = 6
scryptR = 8
scryptDKLen = 32
)
type keyStorePassphrase struct {
keysDirPath string
scryptN int
scryptP int
}
func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) {
// Load the key from the keystore and decrypt its contents
keyjson, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
key, err := DecryptKey(keyjson, auth)
if err != nil {
return nil, err
}
// Make sure we're really operating on the requested key (no swap attacks)
if key.Address != addr {
return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr)
}
return key, nil
}
func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
if err != nil {
return err
}
return writeKeyFile(filename, keyjson)
}
func (ks keyStorePassphrase) JoinPath(filename string) string {
if filepath.IsAbs(filename) {
return filename
} else {
return filepath.Join(ks.keysDirPath, filename)
}
}
// EncryptKey encrypts a key using the specified scrypt parameters into a json
// blob that can be decrypted later on.
func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
authArray := []byte(auth)
salt := randentropy.GetEntropyCSPRNG(32)
derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
if err != nil {
return nil, err
}
encryptKey := derivedKey[:16]
keyBytes0 := crypto.FromECDSA(key.PrivateKey)
keyBytes := common.LeftPadBytes(keyBytes0, 32)
iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
if err != nil {
return nil, err
}
mac := crypto.Keccak256(derivedKey[16:32], cipherText)
scryptParamsJSON := make(map[string]interface{}, 5)
scryptParamsJSON["n"] = scryptN
scryptParamsJSON["r"] = scryptR
scryptParamsJSON["p"] = scryptP
scryptParamsJSON["dklen"] = scryptDKLen
scryptParamsJSON["salt"] = hex.EncodeToString(salt)
cipherParamsJSON := cipherparamsJSON{
IV: hex.EncodeToString(iv),
}
cryptoStruct := cryptoJSON{
Cipher: "aes-128-ctr",
CipherText: hex.EncodeToString(cipherText),
CipherParams: cipherParamsJSON,
KDF: "scrypt",
KDFParams: scryptParamsJSON,
MAC: hex.EncodeToString(mac),
}
encryptedKeyJSONV3 := encryptedKeyJSONV3{
hex.EncodeToString(key.Address[:]),
cryptoStruct,
key.Id.String(),
version,
}
return json.Marshal(encryptedKeyJSONV3)
}
// DecryptKey decrypts a key from a json blob, returning the private key itself.
func DecryptKey(keyjson []byte, auth string) (*Key, error) {
// Parse the json into a simple map to fetch the key version
m := make(map[string]interface{})
if err := json.Unmarshal(keyjson, &m); err != nil {
return nil, err
}
// Depending on the version try to parse one way or another
var (
keyBytes, keyId []byte
err error
)
if version, ok := m["version"].(string); ok && version == "1" {
k := new(encryptedKeyJSONV1)
if err := json.Unmarshal(keyjson, k); err != nil {
return nil, err
}
keyBytes, keyId, err = decryptKeyV1(k, auth)
} else {
k := new(encryptedKeyJSONV3)
if err := json.Unmarshal(keyjson, k); err != nil {
return nil, err
}
keyBytes, keyId, err = decryptKeyV3(k, auth)
}
// Handle any decryption errors and return the key
if err != nil {
return nil, err
}
key := crypto.ToECDSA(keyBytes)
return &Key{
Id: uuid.UUID(keyId),
Address: crypto.PubkeyToAddress(key.PublicKey),
PrivateKey: key,
}, nil
}
func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
if keyProtected.Version != version {
return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
}
if keyProtected.Crypto.Cipher != "aes-128-ctr" {
return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher)
}
keyId = uuid.Parse(keyProtected.Id)
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
if err != nil {
return nil, nil, err
}
iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
if err != nil {
return nil, nil, err
}
cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
if err != nil {
return nil, nil, err
}
derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
if err != nil {
return nil, nil, err
}
calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
if !bytes.Equal(calculatedMAC, mac) {
return nil, nil, ErrDecrypt
}
plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
if err != nil {
return nil, nil, err
}
return plainText, keyId, err
}
func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
keyId = uuid.Parse(keyProtected.Id)
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
if err != nil {
return nil, nil, err
}
iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
if err != nil {
return nil, nil, err
}
cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
if err != nil {
return nil, nil, err
}
derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
if err != nil {
return nil, nil, err
}
calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
if !bytes.Equal(calculatedMAC, mac) {
return nil, nil, ErrDecrypt
}
plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv)
if err != nil {
return nil, nil, err
}
return plainText, keyId, err
}
func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
authArray := []byte(auth)
salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
if err != nil {
return nil, err
}
dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])
if cryptoJSON.KDF == "scrypt" {
n := ensureInt(cryptoJSON.KDFParams["n"])
r := ensureInt(cryptoJSON.KDFParams["r"])
p := ensureInt(cryptoJSON.KDFParams["p"])
return scrypt.Key(authArray, salt, n, r, p, dkLen)
} else if cryptoJSON.KDF == "pbkdf2" {
c := ensureInt(cryptoJSON.KDFParams["c"])
prf := cryptoJSON.KDFParams["prf"].(string)
if prf != "hmac-sha256" {
return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf)
}
key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
return key, nil
}
return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF)
}
// TODO: can we do without this when unmarshalling dynamic JSON?
// why do integers in KDF params end up as float64 and not int after
// unmarshal?
func ensureInt(x interface{}) int {
res, ok := x.(int)
if !ok {
res = int(x.(float64))
}
return res
}

View File

@@ -1,60 +0,0 @@
// Copyright 2016 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 accounts
import (
"io/ioutil"
"testing"
"github.com/ethereum/go-ethereum/common"
)
const (
veryLightScryptN = 2
veryLightScryptP = 1
)
// Tests that a json key file can be decrypted and encrypted in multiple rounds.
func TestKeyEncryptDecrypt(t *testing.T) {
keyjson, err := ioutil.ReadFile("testdata/very-light-scrypt.json")
if err != nil {
t.Fatal(err)
}
password := ""
address := common.HexToAddress("45dea0fb0bba44f4fcf290bba71fd57d7117cbb8")
// Do a few rounds of decryption and encryption
for i := 0; i < 3; i++ {
// Try a bad password first
if _, err := DecryptKey(keyjson, password+"bad"); err == nil {
t.Errorf("test %d: json key decrypted with bad password", i)
}
// Decrypt with the correct password
key, err := DecryptKey(keyjson, password)
if err != nil {
t.Errorf("test %d: json key failed to decrypt: %v", i, err)
}
if key.Address != address {
t.Errorf("test %d: key address mismatch: have %x, want %x", i, key.Address, address)
}
// Recrypt with a new password and start over
password += "new data appended"
if keyjson, err = EncryptKey(key, password, veryLightScryptN, veryLightScryptP); err != nil {
t.Errorf("test %d: failed to recrypt key %v", i, err)
}
}
}

View File

@@ -1,62 +0,0 @@
// 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 accounts
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/ethereum/go-ethereum/common"
)
type keyStorePlain struct {
keysDirPath string
}
func (ks keyStorePlain) GetKey(addr common.Address, filename, auth string) (*Key, error) {
fd, err := os.Open(filename)
if err != nil {
return nil, err
}
defer fd.Close()
key := new(Key)
if err := json.NewDecoder(fd).Decode(key); err != nil {
return nil, err
}
if key.Address != addr {
return nil, fmt.Errorf("key content mismatch: have address %x, want %x", key.Address, addr)
}
return key, nil
}
func (ks keyStorePlain) StoreKey(filename string, key *Key, auth string) error {
content, err := json.Marshal(key)
if err != nil {
return err
}
return writeKeyFile(filename, content)
}
func (ks keyStorePlain) JoinPath(filename string) string {
if filepath.IsAbs(filename) {
return filename
} else {
return filepath.Join(ks.keysDirPath, filename)
}
}

View File

@@ -1,253 +0,0 @@
// 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/>.
package accounts
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
func tmpKeyStore(t *testing.T, encrypted bool) (dir string, ks keyStore) {
d, err := ioutil.TempDir("", "geth-keystore-test")
if err != nil {
t.Fatal(err)
}
if encrypted {
ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP}
} else {
ks = &keyStorePlain{d}
}
return d, ks
}
func TestKeyStorePlain(t *testing.T) {
dir, ks := tmpKeyStore(t, false)
defer os.RemoveAll(dir)
pass := "" // not used but required by API
k1, account, err := storeNewKey(ks, rand.Reader, pass)
if err != nil {
t.Fatal(err)
}
k2, err := ks.GetKey(k1.Address, account.File, pass)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(k1.Address, k2.Address) {
t.Fatal(err)
}
if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
t.Fatal(err)
}
}
func TestKeyStorePassphrase(t *testing.T) {
dir, ks := tmpKeyStore(t, true)
defer os.RemoveAll(dir)
pass := "foo"
k1, account, err := storeNewKey(ks, rand.Reader, pass)
if err != nil {
t.Fatal(err)
}
k2, err := ks.GetKey(k1.Address, account.File, pass)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(k1.Address, k2.Address) {
t.Fatal(err)
}
if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
t.Fatal(err)
}
}
func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
dir, ks := tmpKeyStore(t, true)
defer os.RemoveAll(dir)
pass := "foo"
k1, account, err := storeNewKey(ks, rand.Reader, pass)
if err != nil {
t.Fatal(err)
}
if _, err = ks.GetKey(k1.Address, account.File, "bar"); err != ErrDecrypt {
t.Fatalf("wrong error for invalid passphrase\ngot %q\nwant %q", err, ErrDecrypt)
}
}
func TestImportPreSaleKey(t *testing.T) {
dir, ks := tmpKeyStore(t, true)
defer os.RemoveAll(dir)
// file content of a presale key file generated with:
// python pyethsaletool.py genwallet
// with password "foo"
fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
pass := "foo"
account, _, err := importPreSaleKey(ks, []byte(fileContent), pass)
if err != nil {
t.Fatal(err)
}
if account.Address != common.HexToAddress("d4584b5f6229b7be90727b0fc8c6b91bb427821f") {
t.Errorf("imported account has wrong address %x", account.Address)
}
if !strings.HasPrefix(account.File, dir) {
t.Errorf("imported account file not in keystore directory: %q", account.File)
}
}
// Test and utils for the key store tests in the Ethereum JSON tests;
// testdataKeyStoreTests/basic_tests.json
type KeyStoreTestV3 struct {
Json encryptedKeyJSONV3
Password string
Priv string
}
type KeyStoreTestV1 struct {
Json encryptedKeyJSONV1
Password string
Priv string
}
func TestV3_PBKDF2_1(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
testDecryptV3(tests["wikipage_test_vector_pbkdf2"], t)
}
func TestV3_PBKDF2_2(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
testDecryptV3(tests["test1"], t)
}
func TestV3_PBKDF2_3(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
testDecryptV3(tests["python_generated_test_with_odd_iv"], t)
}
func TestV3_PBKDF2_4(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
testDecryptV3(tests["evilnonce"], t)
}
func TestV3_Scrypt_1(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
testDecryptV3(tests["wikipage_test_vector_scrypt"], t)
}
func TestV3_Scrypt_2(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
testDecryptV3(tests["test2"], t)
}
func TestV1_1(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV1("testdata/v1_test_vector.json", t)
testDecryptV1(tests["test1"], t)
}
func TestV1_2(t *testing.T) {
t.Parallel()
ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP}
addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e")
file := "testdata/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
k, err := ks.GetKey(addr, file, "g")
if err != nil {
t.Fatal(err)
}
privHex := hex.EncodeToString(crypto.FromECDSA(k.PrivateKey))
expectedHex := "d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d"
if privHex != expectedHex {
t.Fatal(fmt.Errorf("Unexpected privkey: %v, expected %v", privHex, expectedHex))
}
}
func testDecryptV3(test KeyStoreTestV3, t *testing.T) {
privBytes, _, err := decryptKeyV3(&test.Json, test.Password)
if err != nil {
t.Fatal(err)
}
privHex := hex.EncodeToString(privBytes)
if test.Priv != privHex {
t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
}
}
func testDecryptV1(test KeyStoreTestV1, t *testing.T) {
privBytes, _, err := decryptKeyV1(&test.Json, test.Password)
if err != nil {
t.Fatal(err)
}
privHex := hex.EncodeToString(privBytes)
if test.Priv != privHex {
t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
}
}
func loadKeyStoreTestV3(file string, t *testing.T) map[string]KeyStoreTestV3 {
tests := make(map[string]KeyStoreTestV3)
err := common.LoadJSON(file, &tests)
if err != nil {
t.Fatal(err)
}
return tests
}
func loadKeyStoreTestV1(file string, t *testing.T) map[string]KeyStoreTestV1 {
tests := make(map[string]KeyStoreTestV1)
err := common.LoadJSON(file, &tests)
if err != nil {
t.Fatal(err)
}
return tests
}
func TestKeyForDirectICAP(t *testing.T) {
t.Parallel()
key := NewKeyForDirectICAP(rand.Reader)
if !strings.HasPrefix(key.Address.Hex(), "0x00") {
t.Errorf("Expected first address byte to be zero, have: %s", key.Address.Hex())
}
}
func TestV3_31_Byte_Key(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
testDecryptV3(tests["31_byte_key"], t)
}
func TestV3_30_Byte_Key(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
testDecryptV3(tests["30_byte_key"], t)
}

View File

@@ -0,0 +1,298 @@
// Copyright 2017 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 keystore
import (
"bufio"
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"gopkg.in/fatih/set.v0"
)
// Minimum amount of time between cache reloads. This limit applies if the platform does
// not support change notifications. It also applies if the keystore directory does not
// exist yet, the code will attempt to create a watcher at most this often.
const minReloadInterval = 2 * time.Second
type accountsByURL []accounts.Account
func (s accountsByURL) Len() int { return len(s) }
func (s accountsByURL) Less(i, j int) bool { return s[i].URL.Cmp(s[j].URL) < 0 }
func (s accountsByURL) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// AmbiguousAddrError is returned when attempting to unlock
// an address for which more than one file exists.
type AmbiguousAddrError struct {
Addr common.Address
Matches []accounts.Account
}
func (err *AmbiguousAddrError) Error() string {
files := ""
for i, a := range err.Matches {
files += a.URL.Path
if i < len(err.Matches)-1 {
files += ", "
}
}
return fmt.Sprintf("multiple keys match address (%s)", files)
}
// accountCache is a live index of all accounts in the keystore.
type accountCache struct {
keydir string
watcher *watcher
mu sync.Mutex
all accountsByURL
byAddr map[common.Address][]accounts.Account
throttle *time.Timer
notify chan struct{}
fileC fileCache
}
func newAccountCache(keydir string) (*accountCache, chan struct{}) {
ac := &accountCache{
keydir: keydir,
byAddr: make(map[common.Address][]accounts.Account),
notify: make(chan struct{}, 1),
fileC: fileCache{all: set.NewNonTS()},
}
ac.watcher = newWatcher(ac)
return ac, ac.notify
}
func (ac *accountCache) accounts() []accounts.Account {
ac.maybeReload()
ac.mu.Lock()
defer ac.mu.Unlock()
cpy := make([]accounts.Account, len(ac.all))
copy(cpy, ac.all)
return cpy
}
func (ac *accountCache) hasAddress(addr common.Address) bool {
ac.maybeReload()
ac.mu.Lock()
defer ac.mu.Unlock()
return len(ac.byAddr[addr]) > 0
}
func (ac *accountCache) add(newAccount accounts.Account) {
ac.mu.Lock()
defer ac.mu.Unlock()
i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Cmp(newAccount.URL) >= 0 })
if i < len(ac.all) && ac.all[i] == newAccount {
return
}
// newAccount is not in the cache.
ac.all = append(ac.all, accounts.Account{})
copy(ac.all[i+1:], ac.all[i:])
ac.all[i] = newAccount
ac.byAddr[newAccount.Address] = append(ac.byAddr[newAccount.Address], newAccount)
}
// note: removed needs to be unique here (i.e. both File and Address must be set).
func (ac *accountCache) delete(removed accounts.Account) {
ac.mu.Lock()
defer ac.mu.Unlock()
ac.all = removeAccount(ac.all, removed)
if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 {
delete(ac.byAddr, removed.Address)
} else {
ac.byAddr[removed.Address] = ba
}
}
// deleteByFile removes an account referenced by the given path.
func (ac *accountCache) deleteByFile(path string) {
ac.mu.Lock()
defer ac.mu.Unlock()
i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Path >= path })
if i < len(ac.all) && ac.all[i].URL.Path == path {
removed := ac.all[i]
ac.all = append(ac.all[:i], ac.all[i+1:]...)
if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 {
delete(ac.byAddr, removed.Address)
} else {
ac.byAddr[removed.Address] = ba
}
}
}
func removeAccount(slice []accounts.Account, elem accounts.Account) []accounts.Account {
for i := range slice {
if slice[i] == elem {
return append(slice[:i], slice[i+1:]...)
}
}
return slice
}
// find returns the cached account for address if there is a unique match.
// The exact matching rules are explained by the documentation of accounts.Account.
// Callers must hold ac.mu.
func (ac *accountCache) find(a accounts.Account) (accounts.Account, error) {
// Limit search to address candidates if possible.
matches := ac.all
if (a.Address != common.Address{}) {
matches = ac.byAddr[a.Address]
}
if a.URL.Path != "" {
// If only the basename is specified, complete the path.
if !strings.ContainsRune(a.URL.Path, filepath.Separator) {
a.URL.Path = filepath.Join(ac.keydir, a.URL.Path)
}
for i := range matches {
if matches[i].URL == a.URL {
return matches[i], nil
}
}
if (a.Address == common.Address{}) {
return accounts.Account{}, ErrNoMatch
}
}
switch len(matches) {
case 1:
return matches[0], nil
case 0:
return accounts.Account{}, ErrNoMatch
default:
err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]accounts.Account, len(matches))}
copy(err.Matches, matches)
sort.Sort(accountsByURL(err.Matches))
return accounts.Account{}, err
}
}
func (ac *accountCache) maybeReload() {
ac.mu.Lock()
if ac.watcher.running {
ac.mu.Unlock()
return // A watcher is running and will keep the cache up-to-date.
}
if ac.throttle == nil {
ac.throttle = time.NewTimer(0)
} else {
select {
case <-ac.throttle.C:
default:
ac.mu.Unlock()
return // The cache was reloaded recently.
}
}
// No watcher running, start it.
ac.watcher.start()
ac.throttle.Reset(minReloadInterval)
ac.mu.Unlock()
ac.scanAccounts()
}
func (ac *accountCache) close() {
ac.mu.Lock()
ac.watcher.close()
if ac.throttle != nil {
ac.throttle.Stop()
}
if ac.notify != nil {
close(ac.notify)
ac.notify = nil
}
ac.mu.Unlock()
}
// scanAccounts checks if any changes have occurred on the filesystem, and
// updates the account cache accordingly
func (ac *accountCache) scanAccounts() error {
// Scan the entire folder metadata for file changes
creates, deletes, updates, err := ac.fileC.scan(ac.keydir)
if err != nil {
log.Debug("Failed to reload keystore contents", "err", err)
return err
}
if creates.Size() == 0 && deletes.Size() == 0 && updates.Size() == 0 {
return nil
}
// Create a helper method to scan the contents of the key files
var (
buf = new(bufio.Reader)
key struct {
Address string `json:"address"`
}
)
readAccount := func(path string) *accounts.Account {
fd, err := os.Open(path)
if err != nil {
log.Trace("Failed to open keystore file", "path", path, "err", err)
return nil
}
defer fd.Close()
buf.Reset(fd)
// Parse the address.
key.Address = ""
err = json.NewDecoder(buf).Decode(&key)
addr := common.HexToAddress(key.Address)
switch {
case err != nil:
log.Debug("Failed to decode keystore key", "path", path, "err", err)
case (addr == common.Address{}):
log.Debug("Failed to decode keystore key", "path", path, "err", "missing or zero address")
default:
return &accounts.Account{Address: addr, URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}}
}
return nil
}
// Process all the file diffs
start := time.Now()
for _, p := range creates.List() {
if a := readAccount(p.(string)); a != nil {
ac.add(*a)
}
}
for _, p := range deletes.List() {
ac.deleteByFile(p.(string))
}
for _, p := range updates.List() {
path := p.(string)
ac.deleteByFile(path)
if a := readAccount(path); a != nil {
ac.add(*a)
}
}
end := time.Now()
select {
case ac.notify <- struct{}{}:
default:
}
log.Trace("Handled keystore changes", "time", end.Sub(start))
return nil
}

View File

@@ -0,0 +1,406 @@
// Copyright 2017 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 keystore
import (
"fmt"
"io/ioutil"
"math/rand"
"os"
"path/filepath"
"reflect"
"sort"
"testing"
"time"
"github.com/cespare/cp"
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
)
var (
cachetestDir, _ = filepath.Abs(filepath.Join("testdata", "keystore"))
cachetestAccounts = []accounts.Account{
{
Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8")},
},
{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "aaa")},
},
{
Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "zzz")},
},
}
)
func TestWatchNewFile(t *testing.T) {
t.Parallel()
dir, ks := tmpKeyStore(t, false)
defer os.RemoveAll(dir)
// Ensure the watcher is started before adding any files.
ks.Accounts()
time.Sleep(1000 * time.Millisecond)
// Move in the files.
wantAccounts := make([]accounts.Account, len(cachetestAccounts))
for i := range cachetestAccounts {
wantAccounts[i] = accounts.Account{
Address: cachetestAccounts[i].Address,
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, filepath.Base(cachetestAccounts[i].URL.Path))},
}
if err := cp.CopyFile(wantAccounts[i].URL.Path, cachetestAccounts[i].URL.Path); err != nil {
t.Fatal(err)
}
}
// ks should see the accounts.
var list []accounts.Account
for d := 200 * time.Millisecond; d < 5*time.Second; d *= 2 {
list = ks.Accounts()
if reflect.DeepEqual(list, wantAccounts) {
// ks should have also received change notifications
select {
case <-ks.changes:
default:
t.Fatalf("wasn't notified of new accounts")
}
return
}
time.Sleep(d)
}
t.Errorf("got %s, want %s", spew.Sdump(list), spew.Sdump(wantAccounts))
}
func TestWatchNoDir(t *testing.T) {
t.Parallel()
// Create ks but not the directory that it watches.
rand.Seed(time.Now().UnixNano())
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watch-test-%d-%d", os.Getpid(), rand.Int()))
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
list := ks.Accounts()
if len(list) > 0 {
t.Error("initial account list not empty:", list)
}
time.Sleep(100 * time.Millisecond)
// Create the directory and copy a key file into it.
os.MkdirAll(dir, 0700)
defer os.RemoveAll(dir)
file := filepath.Join(dir, "aaa")
if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil {
t.Fatal(err)
}
// ks should see the account.
wantAccounts := []accounts.Account{cachetestAccounts[0]}
wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
for d := 200 * time.Millisecond; d < 8*time.Second; d *= 2 {
list = ks.Accounts()
if reflect.DeepEqual(list, wantAccounts) {
// ks should have also received change notifications
select {
case <-ks.changes:
default:
t.Fatalf("wasn't notified of new accounts")
}
return
}
time.Sleep(d)
}
t.Errorf("\ngot %v\nwant %v", list, wantAccounts)
}
func TestCacheInitialReload(t *testing.T) {
cache, _ := newAccountCache(cachetestDir)
accounts := cache.accounts()
if !reflect.DeepEqual(accounts, cachetestAccounts) {
t.Fatalf("got initial accounts: %swant %s", spew.Sdump(accounts), spew.Sdump(cachetestAccounts))
}
}
func TestCacheAddDeleteOrder(t *testing.T) {
cache, _ := newAccountCache("testdata/no-such-dir")
cache.watcher.running = true // prevent unexpected reloads
accs := []accounts.Account{
{
Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: "-309830980"},
},
{
Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: "ggg"},
},
{
Address: common.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: "zzzzzz-the-very-last-one.keyXXX"},
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: "SOMETHING.key"},
},
{
Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8"},
},
{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: "aaa"},
},
{
Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: "zzz"},
},
}
for _, a := range accs {
cache.add(a)
}
// Add some of them twice to check that they don't get reinserted.
cache.add(accs[0])
cache.add(accs[2])
// Check that the account list is sorted by filename.
wantAccounts := make([]accounts.Account, len(accs))
copy(wantAccounts, accs)
sort.Sort(accountsByURL(wantAccounts))
list := cache.accounts()
if !reflect.DeepEqual(list, wantAccounts) {
t.Fatalf("got accounts: %s\nwant %s", spew.Sdump(accs), spew.Sdump(wantAccounts))
}
for _, a := range accs {
if !cache.hasAddress(a.Address) {
t.Errorf("expected hasAccount(%x) to return true", a.Address)
}
}
if cache.hasAddress(common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e")) {
t.Errorf("expected hasAccount(%x) to return false", common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"))
}
// Delete a few keys from the cache.
for i := 0; i < len(accs); i += 2 {
cache.delete(wantAccounts[i])
}
cache.delete(accounts.Account{Address: common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"), URL: accounts.URL{Scheme: KeyStoreScheme, Path: "something"}})
// Check content again after deletion.
wantAccountsAfterDelete := []accounts.Account{
wantAccounts[1],
wantAccounts[3],
wantAccounts[5],
}
list = cache.accounts()
if !reflect.DeepEqual(list, wantAccountsAfterDelete) {
t.Fatalf("got accounts after delete: %s\nwant %s", spew.Sdump(list), spew.Sdump(wantAccountsAfterDelete))
}
for _, a := range wantAccountsAfterDelete {
if !cache.hasAddress(a.Address) {
t.Errorf("expected hasAccount(%x) to return true", a.Address)
}
}
if cache.hasAddress(wantAccounts[0].Address) {
t.Errorf("expected hasAccount(%x) to return false", wantAccounts[0].Address)
}
}
func TestCacheFind(t *testing.T) {
dir := filepath.Join("testdata", "dir")
cache, _ := newAccountCache(dir)
cache.watcher.running = true // prevent unexpected reloads
accs := []accounts.Account{
{
Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "a.key")},
},
{
Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "b.key")},
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "c.key")},
},
{
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "c2.key")},
},
}
for _, a := range accs {
cache.add(a)
}
nomatchAccount := accounts.Account{
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "something")},
}
tests := []struct {
Query accounts.Account
WantResult accounts.Account
WantError error
}{
// by address
{Query: accounts.Account{Address: accs[0].Address}, WantResult: accs[0]},
// by file
{Query: accounts.Account{URL: accs[0].URL}, WantResult: accs[0]},
// by basename
{Query: accounts.Account{URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Base(accs[0].URL.Path)}}, WantResult: accs[0]},
// by file and address
{Query: accs[0], WantResult: accs[0]},
// ambiguous address, tie resolved by file
{Query: accs[2], WantResult: accs[2]},
// ambiguous address error
{
Query: accounts.Account{Address: accs[2].Address},
WantError: &AmbiguousAddrError{
Addr: accs[2].Address,
Matches: []accounts.Account{accs[2], accs[3]},
},
},
// no match error
{Query: nomatchAccount, WantError: ErrNoMatch},
{Query: accounts.Account{URL: nomatchAccount.URL}, WantError: ErrNoMatch},
{Query: accounts.Account{URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Base(nomatchAccount.URL.Path)}}, WantError: ErrNoMatch},
{Query: accounts.Account{Address: nomatchAccount.Address}, WantError: ErrNoMatch},
}
for i, test := range tests {
a, err := cache.find(test.Query)
if !reflect.DeepEqual(err, test.WantError) {
t.Errorf("test %d: error mismatch for query %v\ngot %q\nwant %q", i, test.Query, err, test.WantError)
continue
}
if a != test.WantResult {
t.Errorf("test %d: result mismatch for query %v\ngot %v\nwant %v", i, test.Query, a, test.WantResult)
continue
}
}
}
func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error {
var list []accounts.Account
for d := 200 * time.Millisecond; d < 8*time.Second; d *= 2 {
list = ks.Accounts()
if reflect.DeepEqual(list, wantAccounts) {
// ks should have also received change notifications
select {
case <-ks.changes:
default:
return fmt.Errorf("wasn't notified of new accounts")
}
return nil
}
time.Sleep(d)
}
return fmt.Errorf("\ngot %v\nwant %v", list, wantAccounts)
}
// TestUpdatedKeyfileContents tests that updating the contents of a keystore file
// is noticed by the watcher, and the account cache is updated accordingly
func TestUpdatedKeyfileContents(t *testing.T) {
t.Parallel()
// Create a temporary kesytore to test with
rand.Seed(time.Now().UnixNano())
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watch-test-%d-%d", os.Getpid(), rand.Int()))
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
list := ks.Accounts()
if len(list) > 0 {
t.Error("initial account list not empty:", list)
}
time.Sleep(100 * time.Millisecond)
// Create the directory and copy a key file into it.
os.MkdirAll(dir, 0700)
defer os.RemoveAll(dir)
file := filepath.Join(dir, "aaa")
// Place one of our testfiles in there
if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil {
t.Fatal(err)
}
// ks should see the account.
wantAccounts := []accounts.Account{cachetestAccounts[0]}
wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
if err := waitForAccounts(wantAccounts, ks); err != nil {
t.Error(err)
return
}
// needed so that modTime of `file` is different to its current value after forceCopyFile
time.Sleep(1000 * time.Millisecond)
// Now replace file contents
if err := forceCopyFile(file, cachetestAccounts[1].URL.Path); err != nil {
t.Fatal(err)
return
}
wantAccounts = []accounts.Account{cachetestAccounts[1]}
wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
if err := waitForAccounts(wantAccounts, ks); err != nil {
t.Errorf("First replacement failed")
t.Error(err)
return
}
// needed so that modTime of `file` is different to its current value after forceCopyFile
time.Sleep(1000 * time.Millisecond)
// Now replace file contents again
if err := forceCopyFile(file, cachetestAccounts[2].URL.Path); err != nil {
t.Fatal(err)
return
}
wantAccounts = []accounts.Account{cachetestAccounts[2]}
wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
if err := waitForAccounts(wantAccounts, ks); err != nil {
t.Errorf("Second replacement failed")
t.Error(err)
return
}
// needed so that modTime of `file` is different to its current value after ioutil.WriteFile
time.Sleep(1000 * time.Millisecond)
// Now replace file contents with crap
if err := ioutil.WriteFile(file, []byte("foo"), 0644); err != nil {
t.Fatal(err)
return
}
if err := waitForAccounts([]accounts.Account{}, ks); err != nil {
t.Errorf("Emptying account file failed")
t.Error(err)
return
}
}
// forceCopyFile is like cp.CopyFile, but doesn't complain if the destination exists.
func forceCopyFile(dst, src string) error {
data, err := ioutil.ReadFile(src)
if err != nil {
return err
}
return ioutil.WriteFile(dst, data, 0644)
}

View File

@@ -0,0 +1,102 @@
// Copyright 2017 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 keystore
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/ethereum/go-ethereum/log"
set "gopkg.in/fatih/set.v0"
)
// fileCache is a cache of files seen during scan of keystore.
type fileCache struct {
all *set.SetNonTS // Set of all files from the keystore folder
lastMod time.Time // Last time instance when a file was modified
mu sync.RWMutex
}
// scan performs a new scan on the given directory, compares against the already
// cached filenames, and returns file sets: creates, deletes, updates.
func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Interface, error) {
t0 := time.Now()
// List all the failes from the keystore folder
files, err := ioutil.ReadDir(keyDir)
if err != nil {
return nil, nil, nil, err
}
t1 := time.Now()
fc.mu.Lock()
defer fc.mu.Unlock()
// Iterate all the files and gather their metadata
all := set.NewNonTS()
mods := set.NewNonTS()
var newLastMod time.Time
for _, fi := range files {
// Skip any non-key files from the folder
path := filepath.Join(keyDir, fi.Name())
if skipKeyFile(fi) {
log.Trace("Ignoring file on account scan", "path", path)
continue
}
// Gather the set of all and fresly modified files
all.Add(path)
modified := fi.ModTime()
if modified.After(fc.lastMod) {
mods.Add(path)
}
if modified.After(newLastMod) {
newLastMod = modified
}
}
t2 := time.Now()
// Update the tracked files and return the three sets
deletes := set.Difference(fc.all, all) // Deletes = previous - current
creates := set.Difference(all, fc.all) // Creates = current - previous
updates := set.Difference(mods, creates) // Updates = modified - creates
fc.all, fc.lastMod = all, newLastMod
t3 := time.Now()
// Report on the scanning stats and return
log.Debug("FS scan times", "list", t1.Sub(t0), "set", t2.Sub(t1), "diff", t3.Sub(t2))
return creates, deletes, updates, nil
}
// skipKeyFile ignores editor backups, hidden files and folders/symlinks.
func skipKeyFile(fi os.FileInfo) bool {
// Skip editor backups and UNIX-style hidden files.
if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") {
return true
}
// Skip misc special files, directories (yes, symlinks too).
if fi.IsDir() || fi.Mode()&os.ModeType != 0 {
return true
}
return false
}

View File

@@ -14,7 +14,7 @@
// 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 accounts
package keystore
import (
"bytes"
@@ -29,9 +29,9 @@ import (
"strings"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/pborman/uuid"
)
@@ -91,14 +91,6 @@ type cipherparamsJSON struct {
IV string `json:"iv"`
}
type scryptParamsJSON struct {
N int `json:"n"`
R int `json:"r"`
P int `json:"p"`
DkLen int `json:"dklen"`
Salt string `json:"salt"`
}
func (k *Key) MarshalJSON() (j []byte, err error) {
jStruct := plainKeyJSON{
hex.EncodeToString(k.Address[:]),
@@ -124,14 +116,13 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
if err != nil {
return err
}
privkey, err := hex.DecodeString(keyJSON.PrivateKey)
privkey, err := crypto.HexToECDSA(keyJSON.PrivateKey)
if err != nil {
return err
}
k.Address = common.BytesToAddress(addr)
k.PrivateKey = crypto.ToECDSA(privkey)
k.PrivateKey = privkey
return nil
}
@@ -156,7 +147,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key {
panic("key generation: could not read from random source: " + err.Error())
}
reader := bytes.NewReader(randBytes)
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), reader)
if err != nil {
panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
}
@@ -168,20 +159,20 @@ func NewKeyForDirectICAP(rand io.Reader) *Key {
}
func newKey(rand io.Reader) (*Key, error) {
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), rand)
privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand)
if err != nil {
return nil, err
}
return newKeyFromECDSA(privateKeyECDSA), nil
}
func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, Account, error) {
func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Account, error) {
key, err := newKey(rand)
if err != nil {
return nil, Account{}, err
return nil, accounts.Account{}, err
}
a := Account{Address: key.Address, File: ks.JoinPath(keyFileName(key.Address))}
if err := ks.StoreKey(a.File, key, auth); err != nil {
a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}}
if err := ks.StoreKey(a.URL.Path, key, auth); err != nil {
zeroKey(key.PrivateKey)
return nil, a, err
}

View File

@@ -0,0 +1,493 @@
// Copyright 2017 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 keystore implements encrypted storage of secp256k1 private keys.
//
// Keys are stored as encrypted JSON files according to the Web3 Secret Storage specification.
// See https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition for more information.
package keystore
import (
"crypto/ecdsa"
crand "crypto/rand"
"errors"
"fmt"
"math/big"
"os"
"path/filepath"
"reflect"
"runtime"
"sync"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/event"
)
var (
ErrLocked = accounts.NewAuthNeededError("password or unlock")
ErrNoMatch = errors.New("no key for given address or file")
ErrDecrypt = errors.New("could not decrypt key with given passphrase")
)
// KeyStoreType is the reflect type of a keystore backend.
var KeyStoreType = reflect.TypeOf(&KeyStore{})
// KeyStoreScheme is the protocol scheme prefixing account and wallet URLs.
var KeyStoreScheme = "keystore"
// Maximum time between wallet refreshes (if filesystem notifications don't work).
const walletRefreshCycle = 3 * time.Second
// KeyStore manages a key storage directory on disk.
type KeyStore struct {
storage keyStore // Storage backend, might be cleartext or encrypted
cache *accountCache // In-memory account cache over the filesystem storage
changes chan struct{} // Channel receiving change notifications from the cache
unlocked map[common.Address]*unlocked // Currently unlocked account (decrypted private keys)
wallets []accounts.Wallet // Wallet wrappers around the individual key files
updateFeed event.Feed // Event feed to notify wallet additions/removals
updateScope event.SubscriptionScope // Subscription scope tracking current live listeners
updating bool // Whether the event notification loop is running
mu sync.RWMutex
}
type unlocked struct {
*Key
abort chan struct{}
}
// NewKeyStore creates a keystore for the given directory.
func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore {
keydir, _ = filepath.Abs(keydir)
ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP}}
ks.init(keydir)
return ks
}
// NewPlaintextKeyStore creates a keystore for the given directory.
// Deprecated: Use NewKeyStore.
func NewPlaintextKeyStore(keydir string) *KeyStore {
keydir, _ = filepath.Abs(keydir)
ks := &KeyStore{storage: &keyStorePlain{keydir}}
ks.init(keydir)
return ks
}
func (ks *KeyStore) init(keydir string) {
// Lock the mutex since the account cache might call back with events
ks.mu.Lock()
defer ks.mu.Unlock()
// Initialize the set of unlocked keys and the account cache
ks.unlocked = make(map[common.Address]*unlocked)
ks.cache, ks.changes = newAccountCache(keydir)
// TODO: In order for this finalizer to work, there must be no references
// to ks. addressCache doesn't keep a reference but unlocked keys do,
// so the finalizer will not trigger until all timed unlocks have expired.
runtime.SetFinalizer(ks, func(m *KeyStore) {
m.cache.close()
})
// Create the initial list of wallets from the cache
accs := ks.cache.accounts()
ks.wallets = make([]accounts.Wallet, len(accs))
for i := 0; i < len(accs); i++ {
ks.wallets[i] = &keystoreWallet{account: accs[i], keystore: ks}
}
}
// Wallets implements accounts.Backend, returning all single-key wallets from the
// keystore directory.
func (ks *KeyStore) Wallets() []accounts.Wallet {
// Make sure the list of wallets is in sync with the account cache
ks.refreshWallets()
ks.mu.RLock()
defer ks.mu.RUnlock()
cpy := make([]accounts.Wallet, len(ks.wallets))
copy(cpy, ks.wallets)
return cpy
}
// refreshWallets retrieves the current account list and based on that does any
// necessary wallet refreshes.
func (ks *KeyStore) refreshWallets() {
// Retrieve the current list of accounts
ks.mu.Lock()
accs := ks.cache.accounts()
// Transform the current list of wallets into the new one
wallets := make([]accounts.Wallet, 0, len(accs))
events := []accounts.WalletEvent{}
for _, account := range accs {
// Drop wallets while they were in front of the next account
for len(ks.wallets) > 0 && ks.wallets[0].URL().Cmp(account.URL) < 0 {
events = append(events, accounts.WalletEvent{Wallet: ks.wallets[0], Kind: accounts.WalletDropped})
ks.wallets = ks.wallets[1:]
}
// If there are no more wallets or the account is before the next, wrap new wallet
if len(ks.wallets) == 0 || ks.wallets[0].URL().Cmp(account.URL) > 0 {
wallet := &keystoreWallet{account: account, keystore: ks}
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived})
wallets = append(wallets, wallet)
continue
}
// If the account is the same as the first wallet, keep it
if ks.wallets[0].Accounts()[0] == account {
wallets = append(wallets, ks.wallets[0])
ks.wallets = ks.wallets[1:]
continue
}
}
// Drop any leftover wallets and set the new batch
for _, wallet := range ks.wallets {
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletDropped})
}
ks.wallets = wallets
ks.mu.Unlock()
// Fire all wallet events and return
for _, event := range events {
ks.updateFeed.Send(event)
}
}
// Subscribe implements accounts.Backend, creating an async subscription to
// receive notifications on the addition or removal of keystore wallets.
func (ks *KeyStore) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription {
// We need the mutex to reliably start/stop the update loop
ks.mu.Lock()
defer ks.mu.Unlock()
// Subscribe the caller and track the subscriber count
sub := ks.updateScope.Track(ks.updateFeed.Subscribe(sink))
// Subscribers require an active notification loop, start it
if !ks.updating {
ks.updating = true
go ks.updater()
}
return sub
}
// updater is responsible for maintaining an up-to-date list of wallets stored in
// the keystore, and for firing wallet addition/removal events. It listens for
// account change events from the underlying account cache, and also periodically
// forces a manual refresh (only triggers for systems where the filesystem notifier
// is not running).
func (ks *KeyStore) updater() {
for {
// Wait for an account update or a refresh timeout
select {
case <-ks.changes:
case <-time.After(walletRefreshCycle):
}
// Run the wallet refresher
ks.refreshWallets()
// If all our subscribers left, stop the updater
ks.mu.Lock()
if ks.updateScope.Count() == 0 {
ks.updating = false
ks.mu.Unlock()
return
}
ks.mu.Unlock()
}
}
// HasAddress reports whether a key with the given address is present.
func (ks *KeyStore) HasAddress(addr common.Address) bool {
return ks.cache.hasAddress(addr)
}
// Accounts returns all key files present in the directory.
func (ks *KeyStore) Accounts() []accounts.Account {
return ks.cache.accounts()
}
// Delete deletes the key matched by account if the passphrase is correct.
// If the account contains no filename, the address must match a unique key.
func (ks *KeyStore) Delete(a accounts.Account, passphrase string) error {
// Decrypting the key isn't really necessary, but we do
// it anyway to check the password and zero out the key
// immediately afterwards.
a, key, err := ks.getDecryptedKey(a, passphrase)
if key != nil {
zeroKey(key.PrivateKey)
}
if err != nil {
return err
}
// The order is crucial here. The key is dropped from the
// cache after the file is gone so that a reload happening in
// between won't insert it into the cache again.
err = os.Remove(a.URL.Path)
if err == nil {
ks.cache.delete(a)
ks.refreshWallets()
}
return err
}
// SignHash calculates a ECDSA signature for the given hash. The produced
// signature is in the [R || S || V] format where V is 0 or 1.
func (ks *KeyStore) SignHash(a accounts.Account, hash []byte) ([]byte, error) {
// Look up the key to sign with and abort if it cannot be found
ks.mu.RLock()
defer ks.mu.RUnlock()
unlockedKey, found := ks.unlocked[a.Address]
if !found {
return nil, ErrLocked
}
// Sign the hash using plain ECDSA operations
return crypto.Sign(hash, unlockedKey.PrivateKey)
}
// SignTx signs the given transaction with the requested account.
func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
// Look up the key to sign with and abort if it cannot be found
ks.mu.RLock()
defer ks.mu.RUnlock()
unlockedKey, found := ks.unlocked[a.Address]
if !found {
return nil, ErrLocked
}
// Depending on the presence of the chain ID, sign with EIP155 or homestead
if chainID != nil {
return types.SignTx(tx, types.NewEIP155Signer(chainID), unlockedKey.PrivateKey)
}
return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey)
}
// SignHashWithPassphrase signs hash if the private key matching the given address
// can be decrypted with the given passphrase. The produced signature is in the
// [R || S || V] format where V is 0 or 1.
func (ks *KeyStore) SignHashWithPassphrase(a accounts.Account, passphrase string, hash []byte) (signature []byte, err error) {
_, key, err := ks.getDecryptedKey(a, passphrase)
if err != nil {
return nil, err
}
defer zeroKey(key.PrivateKey)
return crypto.Sign(hash, key.PrivateKey)
}
// SignTxWithPassphrase signs the transaction if the private key matching the
// given address can be decrypted with the given passphrase.
func (ks *KeyStore) SignTxWithPassphrase(a accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
_, key, err := ks.getDecryptedKey(a, passphrase)
if err != nil {
return nil, err
}
defer zeroKey(key.PrivateKey)
// Depending on the presence of the chain ID, sign with EIP155 or homestead
if chainID != nil {
return types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey)
}
return types.SignTx(tx, types.HomesteadSigner{}, key.PrivateKey)
}
// Unlock unlocks the given account indefinitely.
func (ks *KeyStore) Unlock(a accounts.Account, passphrase string) error {
return ks.TimedUnlock(a, passphrase, 0)
}
// Lock removes the private key with the given address from memory.
func (ks *KeyStore) Lock(addr common.Address) error {
ks.mu.Lock()
if unl, found := ks.unlocked[addr]; found {
ks.mu.Unlock()
ks.expire(addr, unl, time.Duration(0)*time.Nanosecond)
} else {
ks.mu.Unlock()
}
return nil
}
// TimedUnlock unlocks the given account with the passphrase. The account
// stays unlocked for the duration of timeout. A timeout of 0 unlocks the account
// until the program exits. The account must match a unique key file.
//
// If the account address is already unlocked for a duration, TimedUnlock extends or
// shortens the active unlock timeout. If the address was previously unlocked
// indefinitely the timeout is not altered.
func (ks *KeyStore) TimedUnlock(a accounts.Account, passphrase string, timeout time.Duration) error {
a, key, err := ks.getDecryptedKey(a, passphrase)
if err != nil {
return err
}
ks.mu.Lock()
defer ks.mu.Unlock()
u, found := ks.unlocked[a.Address]
if found {
if u.abort == nil {
// The address was unlocked indefinitely, so unlocking
// it with a timeout would be confusing.
zeroKey(key.PrivateKey)
return nil
}
// Terminate the expire goroutine and replace it below.
close(u.abort)
}
if timeout > 0 {
u = &unlocked{Key: key, abort: make(chan struct{})}
go ks.expire(a.Address, u, timeout)
} else {
u = &unlocked{Key: key}
}
ks.unlocked[a.Address] = u
return nil
}
// Find resolves the given account into a unique entry in the keystore.
func (ks *KeyStore) Find(a accounts.Account) (accounts.Account, error) {
ks.cache.maybeReload()
ks.cache.mu.Lock()
a, err := ks.cache.find(a)
ks.cache.mu.Unlock()
return a, err
}
func (ks *KeyStore) getDecryptedKey(a accounts.Account, auth string) (accounts.Account, *Key, error) {
a, err := ks.Find(a)
if err != nil {
return a, nil, err
}
key, err := ks.storage.GetKey(a.Address, a.URL.Path, auth)
return a, key, err
}
func (ks *KeyStore) expire(addr common.Address, u *unlocked, timeout time.Duration) {
t := time.NewTimer(timeout)
defer t.Stop()
select {
case <-u.abort:
// just quit
case <-t.C:
ks.mu.Lock()
// only drop if it's still the same key instance that dropLater
// was launched with. we can check that using pointer equality
// because the map stores a new pointer every time the key is
// unlocked.
if ks.unlocked[addr] == u {
zeroKey(u.PrivateKey)
delete(ks.unlocked, addr)
}
ks.mu.Unlock()
}
}
// NewAccount generates a new key and stores it into the key directory,
// encrypting it with the passphrase.
func (ks *KeyStore) NewAccount(passphrase string) (accounts.Account, error) {
_, account, err := storeNewKey(ks.storage, crand.Reader, passphrase)
if err != nil {
return accounts.Account{}, err
}
// Add the account to the cache immediately rather
// than waiting for file system notifications to pick it up.
ks.cache.add(account)
ks.refreshWallets()
return account, nil
}
// Export exports as a JSON key, encrypted with newPassphrase.
func (ks *KeyStore) Export(a accounts.Account, passphrase, newPassphrase string) (keyJSON []byte, err error) {
_, key, err := ks.getDecryptedKey(a, passphrase)
if err != nil {
return nil, err
}
var N, P int
if store, ok := ks.storage.(*keyStorePassphrase); ok {
N, P = store.scryptN, store.scryptP
} else {
N, P = StandardScryptN, StandardScryptP
}
return EncryptKey(key, newPassphrase, N, P)
}
// Import stores the given encrypted JSON key into the key directory.
func (ks *KeyStore) Import(keyJSON []byte, passphrase, newPassphrase string) (accounts.Account, error) {
key, err := DecryptKey(keyJSON, passphrase)
if key != nil && key.PrivateKey != nil {
defer zeroKey(key.PrivateKey)
}
if err != nil {
return accounts.Account{}, err
}
return ks.importKey(key, newPassphrase)
}
// ImportECDSA stores the given key into the key directory, encrypting it with the passphrase.
func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (accounts.Account, error) {
key := newKeyFromECDSA(priv)
if ks.cache.hasAddress(key.Address) {
return accounts.Account{}, fmt.Errorf("account already exists")
}
return ks.importKey(key, passphrase)
}
func (ks *KeyStore) importKey(key *Key, passphrase string) (accounts.Account, error) {
a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.storage.JoinPath(keyFileName(key.Address))}}
if err := ks.storage.StoreKey(a.URL.Path, key, passphrase); err != nil {
return accounts.Account{}, err
}
ks.cache.add(a)
ks.refreshWallets()
return a, nil
}
// Update changes the passphrase of an existing account.
func (ks *KeyStore) Update(a accounts.Account, passphrase, newPassphrase string) error {
a, key, err := ks.getDecryptedKey(a, passphrase)
if err != nil {
return err
}
return ks.storage.StoreKey(a.URL.Path, key, newPassphrase)
}
// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores
// a key file in the key directory. The key file is encrypted with the same passphrase.
func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (accounts.Account, error) {
a, _, err := importPreSaleKey(ks.storage, keyJSON, passphrase)
if err != nil {
return a, err
}
ks.cache.add(a)
ks.refreshWallets()
return a, nil
}
// zeroKey zeroes a private key in memory.
func zeroKey(k *ecdsa.PrivateKey) {
b := k.D.Bits()
for i := range b {
b[i] = 0
}
}

View File

@@ -0,0 +1,313 @@
// 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/>.
/*
This key store behaves as KeyStorePlain with the difference that
the private key is encrypted and on disk uses another JSON encoding.
The crypto is documented at https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
*/
package keystore
import (
"bytes"
"crypto/aes"
crand "crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/randentropy"
"github.com/pborman/uuid"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/scrypt"
)
const (
keyHeaderKDF = "scrypt"
// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
// memory and taking approximately 1s CPU time on a modern processor.
StandardScryptN = 1 << 18
// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
// memory and taking approximately 1s CPU time on a modern processor.
StandardScryptP = 1
// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
// memory and taking approximately 100ms CPU time on a modern processor.
LightScryptN = 1 << 12
// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
// memory and taking approximately 100ms CPU time on a modern processor.
LightScryptP = 6
scryptR = 8
scryptDKLen = 32
)
type keyStorePassphrase struct {
keysDirPath string
scryptN int
scryptP int
}
func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) {
// Load the key from the keystore and decrypt its contents
keyjson, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
key, err := DecryptKey(keyjson, auth)
if err != nil {
return nil, err
}
// Make sure we're really operating on the requested key (no swap attacks)
if key.Address != addr {
return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr)
}
return key, nil
}
// StoreKey generates a key, encrypts with 'auth' and stores in the given directory
func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, crand.Reader, auth)
return a.Address, err
}
func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
if err != nil {
return err
}
return writeKeyFile(filename, keyjson)
}
func (ks keyStorePassphrase) JoinPath(filename string) string {
if filepath.IsAbs(filename) {
return filename
} else {
return filepath.Join(ks.keysDirPath, filename)
}
}
// EncryptKey encrypts a key using the specified scrypt parameters into a json
// blob that can be decrypted later on.
func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
authArray := []byte(auth)
salt := randentropy.GetEntropyCSPRNG(32)
derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
if err != nil {
return nil, err
}
encryptKey := derivedKey[:16]
keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32)
iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
if err != nil {
return nil, err
}
mac := crypto.Keccak256(derivedKey[16:32], cipherText)
scryptParamsJSON := make(map[string]interface{}, 5)
scryptParamsJSON["n"] = scryptN
scryptParamsJSON["r"] = scryptR
scryptParamsJSON["p"] = scryptP
scryptParamsJSON["dklen"] = scryptDKLen
scryptParamsJSON["salt"] = hex.EncodeToString(salt)
cipherParamsJSON := cipherparamsJSON{
IV: hex.EncodeToString(iv),
}
cryptoStruct := cryptoJSON{
Cipher: "aes-128-ctr",
CipherText: hex.EncodeToString(cipherText),
CipherParams: cipherParamsJSON,
KDF: keyHeaderKDF,
KDFParams: scryptParamsJSON,
MAC: hex.EncodeToString(mac),
}
encryptedKeyJSONV3 := encryptedKeyJSONV3{
hex.EncodeToString(key.Address[:]),
cryptoStruct,
key.Id.String(),
version,
}
return json.Marshal(encryptedKeyJSONV3)
}
// DecryptKey decrypts a key from a json blob, returning the private key itself.
func DecryptKey(keyjson []byte, auth string) (*Key, error) {
// Parse the json into a simple map to fetch the key version
m := make(map[string]interface{})
if err := json.Unmarshal(keyjson, &m); err != nil {
return nil, err
}
// Depending on the version try to parse one way or another
var (
keyBytes, keyId []byte
err error
)
if version, ok := m["version"].(string); ok && version == "1" {
k := new(encryptedKeyJSONV1)
if err := json.Unmarshal(keyjson, k); err != nil {
return nil, err
}
keyBytes, keyId, err = decryptKeyV1(k, auth)
} else {
k := new(encryptedKeyJSONV3)
if err := json.Unmarshal(keyjson, k); err != nil {
return nil, err
}
keyBytes, keyId, err = decryptKeyV3(k, auth)
}
// Handle any decryption errors and return the key
if err != nil {
return nil, err
}
key := crypto.ToECDSAUnsafe(keyBytes)
return &Key{
Id: uuid.UUID(keyId),
Address: crypto.PubkeyToAddress(key.PublicKey),
PrivateKey: key,
}, nil
}
func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
if keyProtected.Version != version {
return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
}
if keyProtected.Crypto.Cipher != "aes-128-ctr" {
return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher)
}
keyId = uuid.Parse(keyProtected.Id)
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
if err != nil {
return nil, nil, err
}
iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
if err != nil {
return nil, nil, err
}
cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
if err != nil {
return nil, nil, err
}
derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
if err != nil {
return nil, nil, err
}
calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
if !bytes.Equal(calculatedMAC, mac) {
return nil, nil, ErrDecrypt
}
plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
if err != nil {
return nil, nil, err
}
return plainText, keyId, err
}
func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
keyId = uuid.Parse(keyProtected.Id)
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
if err != nil {
return nil, nil, err
}
iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
if err != nil {
return nil, nil, err
}
cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
if err != nil {
return nil, nil, err
}
derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
if err != nil {
return nil, nil, err
}
calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
if !bytes.Equal(calculatedMAC, mac) {
return nil, nil, ErrDecrypt
}
plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv)
if err != nil {
return nil, nil, err
}
return plainText, keyId, err
}
func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
authArray := []byte(auth)
salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
if err != nil {
return nil, err
}
dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])
if cryptoJSON.KDF == keyHeaderKDF {
n := ensureInt(cryptoJSON.KDFParams["n"])
r := ensureInt(cryptoJSON.KDFParams["r"])
p := ensureInt(cryptoJSON.KDFParams["p"])
return scrypt.Key(authArray, salt, n, r, p, dkLen)
} else if cryptoJSON.KDF == "pbkdf2" {
c := ensureInt(cryptoJSON.KDFParams["c"])
prf := cryptoJSON.KDFParams["prf"].(string)
if prf != "hmac-sha256" {
return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf)
}
key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
return key, nil
}
return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF)
}
// TODO: can we do without this when unmarshalling dynamic JSON?
// why do integers in KDF params end up as float64 and not int after
// unmarshal?
func ensureInt(x interface{}) int {
res, ok := x.(int)
if !ok {
res = int(x.(float64))
}
return res
}

View File

@@ -0,0 +1,60 @@
// Copyright 2016 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 keystore
import (
"io/ioutil"
"testing"
"github.com/ethereum/go-ethereum/common"
)
const (
veryLightScryptN = 2
veryLightScryptP = 1
)
// Tests that a json key file can be decrypted and encrypted in multiple rounds.
func TestKeyEncryptDecrypt(t *testing.T) {
keyjson, err := ioutil.ReadFile("testdata/very-light-scrypt.json")
if err != nil {
t.Fatal(err)
}
password := ""
address := common.HexToAddress("45dea0fb0bba44f4fcf290bba71fd57d7117cbb8")
// Do a few rounds of decryption and encryption
for i := 0; i < 3; i++ {
// Try a bad password first
if _, err := DecryptKey(keyjson, password+"bad"); err == nil {
t.Errorf("test %d: json key decrypted with bad password", i)
}
// Decrypt with the correct password
key, err := DecryptKey(keyjson, password)
if err != nil {
t.Fatalf("test %d: json key failed to decrypt: %v", i, err)
}
if key.Address != address {
t.Errorf("test %d: key address mismatch: have %x, want %x", i, key.Address, address)
}
// Recrypt with a new password and start over
password += "new data appended"
if keyjson, err = EncryptKey(key, password, veryLightScryptN, veryLightScryptP); err != nil {
t.Errorf("test %d: failed to recrypt key %v", i, err)
}
}
}

View File

@@ -0,0 +1,62 @@
// 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 keystore
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/ethereum/go-ethereum/common"
)
type keyStorePlain struct {
keysDirPath string
}
func (ks keyStorePlain) GetKey(addr common.Address, filename, auth string) (*Key, error) {
fd, err := os.Open(filename)
if err != nil {
return nil, err
}
defer fd.Close()
key := new(Key)
if err := json.NewDecoder(fd).Decode(key); err != nil {
return nil, err
}
if key.Address != addr {
return nil, fmt.Errorf("key content mismatch: have address %x, want %x", key.Address, addr)
}
return key, nil
}
func (ks keyStorePlain) StoreKey(filename string, key *Key, auth string) error {
content, err := json.Marshal(key)
if err != nil {
return err
}
return writeKeyFile(filename, content)
}
func (ks keyStorePlain) JoinPath(filename string) string {
if filepath.IsAbs(filename) {
return filename
} else {
return filepath.Join(ks.keysDirPath, filename)
}
}

View File

@@ -0,0 +1,266 @@
// 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/>.
package keystore
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) {
d, err := ioutil.TempDir("", "geth-keystore-test")
if err != nil {
t.Fatal(err)
}
if encrypted {
ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP}
} else {
ks = &keyStorePlain{d}
}
return d, ks
}
func TestKeyStorePlain(t *testing.T) {
dir, ks := tmpKeyStoreIface(t, false)
defer os.RemoveAll(dir)
pass := "" // not used but required by API
k1, account, err := storeNewKey(ks, rand.Reader, pass)
if err != nil {
t.Fatal(err)
}
k2, err := ks.GetKey(k1.Address, account.URL.Path, pass)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(k1.Address, k2.Address) {
t.Fatal(err)
}
if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
t.Fatal(err)
}
}
func TestKeyStorePassphrase(t *testing.T) {
dir, ks := tmpKeyStoreIface(t, true)
defer os.RemoveAll(dir)
pass := "foo"
k1, account, err := storeNewKey(ks, rand.Reader, pass)
if err != nil {
t.Fatal(err)
}
k2, err := ks.GetKey(k1.Address, account.URL.Path, pass)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(k1.Address, k2.Address) {
t.Fatal(err)
}
if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
t.Fatal(err)
}
}
func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
dir, ks := tmpKeyStoreIface(t, true)
defer os.RemoveAll(dir)
pass := "foo"
k1, account, err := storeNewKey(ks, rand.Reader, pass)
if err != nil {
t.Fatal(err)
}
if _, err = ks.GetKey(k1.Address, account.URL.Path, "bar"); err != ErrDecrypt {
t.Fatalf("wrong error for invalid passphrase\ngot %q\nwant %q", err, ErrDecrypt)
}
}
func TestImportPreSaleKey(t *testing.T) {
dir, ks := tmpKeyStoreIface(t, true)
defer os.RemoveAll(dir)
// file content of a presale key file generated with:
// python pyethsaletool.py genwallet
// with password "foo"
fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
pass := "foo"
account, _, err := importPreSaleKey(ks, []byte(fileContent), pass)
if err != nil {
t.Fatal(err)
}
if account.Address != common.HexToAddress("d4584b5f6229b7be90727b0fc8c6b91bb427821f") {
t.Errorf("imported account has wrong address %x", account.Address)
}
if !strings.HasPrefix(account.URL.Path, dir) {
t.Errorf("imported account file not in keystore directory: %q", account.URL)
}
}
// Test and utils for the key store tests in the Ethereum JSON tests;
// testdataKeyStoreTests/basic_tests.json
type KeyStoreTestV3 struct {
Json encryptedKeyJSONV3
Password string
Priv string
}
type KeyStoreTestV1 struct {
Json encryptedKeyJSONV1
Password string
Priv string
}
func TestV3_PBKDF2_1(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
testDecryptV3(tests["wikipage_test_vector_pbkdf2"], t)
}
var testsSubmodule = filepath.Join("..", "..", "tests", "testdata", "KeyStoreTests")
func skipIfSubmoduleMissing(t *testing.T) {
if !common.FileExist(testsSubmodule) {
t.Skipf("can't find JSON tests from submodule at %s", testsSubmodule)
}
}
func TestV3_PBKDF2_2(t *testing.T) {
skipIfSubmoduleMissing(t)
t.Parallel()
tests := loadKeyStoreTestV3(filepath.Join(testsSubmodule, "basic_tests.json"), t)
testDecryptV3(tests["test1"], t)
}
func TestV3_PBKDF2_3(t *testing.T) {
skipIfSubmoduleMissing(t)
t.Parallel()
tests := loadKeyStoreTestV3(filepath.Join(testsSubmodule, "basic_tests.json"), t)
testDecryptV3(tests["python_generated_test_with_odd_iv"], t)
}
func TestV3_PBKDF2_4(t *testing.T) {
skipIfSubmoduleMissing(t)
t.Parallel()
tests := loadKeyStoreTestV3(filepath.Join(testsSubmodule, "basic_tests.json"), t)
testDecryptV3(tests["evilnonce"], t)
}
func TestV3_Scrypt_1(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
testDecryptV3(tests["wikipage_test_vector_scrypt"], t)
}
func TestV3_Scrypt_2(t *testing.T) {
skipIfSubmoduleMissing(t)
t.Parallel()
tests := loadKeyStoreTestV3(filepath.Join(testsSubmodule, "basic_tests.json"), t)
testDecryptV3(tests["test2"], t)
}
func TestV1_1(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV1("testdata/v1_test_vector.json", t)
testDecryptV1(tests["test1"], t)
}
func TestV1_2(t *testing.T) {
t.Parallel()
ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP}
addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e")
file := "testdata/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
k, err := ks.GetKey(addr, file, "g")
if err != nil {
t.Fatal(err)
}
privHex := hex.EncodeToString(crypto.FromECDSA(k.PrivateKey))
expectedHex := "d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d"
if privHex != expectedHex {
t.Fatal(fmt.Errorf("Unexpected privkey: %v, expected %v", privHex, expectedHex))
}
}
func testDecryptV3(test KeyStoreTestV3, t *testing.T) {
privBytes, _, err := decryptKeyV3(&test.Json, test.Password)
if err != nil {
t.Fatal(err)
}
privHex := hex.EncodeToString(privBytes)
if test.Priv != privHex {
t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
}
}
func testDecryptV1(test KeyStoreTestV1, t *testing.T) {
privBytes, _, err := decryptKeyV1(&test.Json, test.Password)
if err != nil {
t.Fatal(err)
}
privHex := hex.EncodeToString(privBytes)
if test.Priv != privHex {
t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
}
}
func loadKeyStoreTestV3(file string, t *testing.T) map[string]KeyStoreTestV3 {
tests := make(map[string]KeyStoreTestV3)
err := common.LoadJSON(file, &tests)
if err != nil {
t.Fatal(err)
}
return tests
}
func loadKeyStoreTestV1(file string, t *testing.T) map[string]KeyStoreTestV1 {
tests := make(map[string]KeyStoreTestV1)
err := common.LoadJSON(file, &tests)
if err != nil {
t.Fatal(err)
}
return tests
}
func TestKeyForDirectICAP(t *testing.T) {
t.Parallel()
key := NewKeyForDirectICAP(rand.Reader)
if !strings.HasPrefix(key.Address.Hex(), "0x00") {
t.Errorf("Expected first address byte to be zero, have: %s", key.Address.Hex())
}
}
func TestV3_31_Byte_Key(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
testDecryptV3(tests["31_byte_key"], t)
}
func TestV3_30_Byte_Key(t *testing.T) {
t.Parallel()
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
testDecryptV3(tests["30_byte_key"], t)
}

View File

@@ -0,0 +1,387 @@
// Copyright 2017 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 keystore
import (
"io/ioutil"
"math/rand"
"os"
"runtime"
"sort"
"strings"
"testing"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
)
var testSigData = make([]byte, 32)
func TestKeyStore(t *testing.T) {
dir, ks := tmpKeyStore(t, true)
defer os.RemoveAll(dir)
a, err := ks.NewAccount("foo")
if err != nil {
t.Fatal(err)
}
if !strings.HasPrefix(a.URL.Path, dir) {
t.Errorf("account file %s doesn't have dir prefix", a.URL)
}
stat, err := os.Stat(a.URL.Path)
if err != nil {
t.Fatalf("account file %s doesn't exist (%v)", a.URL, err)
}
if runtime.GOOS != "windows" && stat.Mode() != 0600 {
t.Fatalf("account file has wrong mode: got %o, want %o", stat.Mode(), 0600)
}
if !ks.HasAddress(a.Address) {
t.Errorf("HasAccount(%x) should've returned true", a.Address)
}
if err := ks.Update(a, "foo", "bar"); err != nil {
t.Errorf("Update error: %v", err)
}
if err := ks.Delete(a, "bar"); err != nil {
t.Errorf("Delete error: %v", err)
}
if common.FileExist(a.URL.Path) {
t.Errorf("account file %s should be gone after Delete", a.URL)
}
if ks.HasAddress(a.Address) {
t.Errorf("HasAccount(%x) should've returned true after Delete", a.Address)
}
}
func TestSign(t *testing.T) {
dir, ks := tmpKeyStore(t, true)
defer os.RemoveAll(dir)
pass := "" // not used but required by API
a1, err := ks.NewAccount(pass)
if err != nil {
t.Fatal(err)
}
if err := ks.Unlock(a1, ""); err != nil {
t.Fatal(err)
}
if _, err := ks.SignHash(accounts.Account{Address: a1.Address}, testSigData); err != nil {
t.Fatal(err)
}
}
func TestSignWithPassphrase(t *testing.T) {
dir, ks := tmpKeyStore(t, true)
defer os.RemoveAll(dir)
pass := "passwd"
acc, err := ks.NewAccount(pass)
if err != nil {
t.Fatal(err)
}
if _, unlocked := ks.unlocked[acc.Address]; unlocked {
t.Fatal("expected account to be locked")
}
_, err = ks.SignHashWithPassphrase(acc, pass, testSigData)
if err != nil {
t.Fatal(err)
}
if _, unlocked := ks.unlocked[acc.Address]; unlocked {
t.Fatal("expected account to be locked")
}
if _, err = ks.SignHashWithPassphrase(acc, "invalid passwd", testSigData); err == nil {
t.Fatal("expected SignHashWithPassphrase to fail with invalid password")
}
}
func TestTimedUnlock(t *testing.T) {
dir, ks := tmpKeyStore(t, true)
defer os.RemoveAll(dir)
pass := "foo"
a1, err := ks.NewAccount(pass)
if err != nil {
t.Fatal(err)
}
// Signing without passphrase fails because account is locked
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != ErrLocked {
t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err)
}
// Signing with passphrase works
if err = ks.TimedUnlock(a1, pass, 100*time.Millisecond); err != nil {
t.Fatal(err)
}
// Signing without passphrase works because account is temp unlocked
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != nil {
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
}
// Signing fails again after automatic locking
time.Sleep(250 * time.Millisecond)
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != ErrLocked {
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
}
}
func TestOverrideUnlock(t *testing.T) {
dir, ks := tmpKeyStore(t, false)
defer os.RemoveAll(dir)
pass := "foo"
a1, err := ks.NewAccount(pass)
if err != nil {
t.Fatal(err)
}
// Unlock indefinitely.
if err = ks.TimedUnlock(a1, pass, 5*time.Minute); err != nil {
t.Fatal(err)
}
// Signing without passphrase works because account is temp unlocked
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != nil {
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
}
// reset unlock to a shorter period, invalidates the previous unlock
if err = ks.TimedUnlock(a1, pass, 100*time.Millisecond); err != nil {
t.Fatal(err)
}
// Signing without passphrase still works because account is temp unlocked
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != nil {
t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
}
// Signing fails again after automatic locking
time.Sleep(250 * time.Millisecond)
_, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
if err != ErrLocked {
t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
}
}
// This test should fail under -race if signing races the expiration goroutine.
func TestSignRace(t *testing.T) {
dir, ks := tmpKeyStore(t, false)
defer os.RemoveAll(dir)
// Create a test account.
a1, err := ks.NewAccount("")
if err != nil {
t.Fatal("could not create the test account", err)
}
if err := ks.TimedUnlock(a1, "", 15*time.Millisecond); err != nil {
t.Fatal("could not unlock the test account", err)
}
end := time.Now().Add(500 * time.Millisecond)
for time.Now().Before(end) {
if _, err := ks.SignHash(accounts.Account{Address: a1.Address}, testSigData); err == ErrLocked {
return
} else if err != nil {
t.Errorf("Sign error: %v", err)
return
}
time.Sleep(1 * time.Millisecond)
}
t.Errorf("Account did not lock within the timeout")
}
// Tests that the wallet notifier loop starts and stops correctly based on the
// addition and removal of wallet event subscriptions.
func TestWalletNotifierLifecycle(t *testing.T) {
// Create a temporary kesytore to test with
dir, ks := tmpKeyStore(t, false)
defer os.RemoveAll(dir)
// Ensure that the notification updater is not running yet
time.Sleep(250 * time.Millisecond)
ks.mu.RLock()
updating := ks.updating
ks.mu.RUnlock()
if updating {
t.Errorf("wallet notifier running without subscribers")
}
// Subscribe to the wallet feed and ensure the updater boots up
updates := make(chan accounts.WalletEvent)
subs := make([]event.Subscription, 2)
for i := 0; i < len(subs); i++ {
// Create a new subscription
subs[i] = ks.Subscribe(updates)
// Ensure the notifier comes online
time.Sleep(250 * time.Millisecond)
ks.mu.RLock()
updating = ks.updating
ks.mu.RUnlock()
if !updating {
t.Errorf("sub %d: wallet notifier not running after subscription", i)
}
}
// Unsubscribe and ensure the updater terminates eventually
for i := 0; i < len(subs); i++ {
// Close an existing subscription
subs[i].Unsubscribe()
// Ensure the notifier shuts down at and only at the last close
for k := 0; k < int(walletRefreshCycle/(250*time.Millisecond))+2; k++ {
ks.mu.RLock()
updating = ks.updating
ks.mu.RUnlock()
if i < len(subs)-1 && !updating {
t.Fatalf("sub %d: event notifier stopped prematurely", i)
}
if i == len(subs)-1 && !updating {
return
}
time.Sleep(250 * time.Millisecond)
}
}
t.Errorf("wallet notifier didn't terminate after unsubscribe")
}
type walletEvent struct {
accounts.WalletEvent
a accounts.Account
}
// Tests that wallet notifications and correctly fired when accounts are added
// or deleted from the keystore.
func TestWalletNotifications(t *testing.T) {
dir, ks := tmpKeyStore(t, false)
defer os.RemoveAll(dir)
// Subscribe to the wallet feed and collect events.
var (
events []walletEvent
updates = make(chan accounts.WalletEvent)
sub = ks.Subscribe(updates)
)
defer sub.Unsubscribe()
go func() {
for {
select {
case ev := <-updates:
events = append(events, walletEvent{ev, ev.Wallet.Accounts()[0]})
case <-sub.Err():
close(updates)
return
}
}
}()
// Randomly add and remove accounts.
var (
live = make(map[common.Address]accounts.Account)
wantEvents []walletEvent
)
for i := 0; i < 1024; i++ {
if create := len(live) == 0 || rand.Int()%4 > 0; create {
// Add a new account and ensure wallet notifications arrives
account, err := ks.NewAccount("")
if err != nil {
t.Fatalf("failed to create test account: %v", err)
}
live[account.Address] = account
wantEvents = append(wantEvents, walletEvent{accounts.WalletEvent{Kind: accounts.WalletArrived}, account})
} else {
// Delete a random account.
var account accounts.Account
for _, a := range live {
account = a
break
}
if err := ks.Delete(account, ""); err != nil {
t.Fatalf("failed to delete test account: %v", err)
}
delete(live, account.Address)
wantEvents = append(wantEvents, walletEvent{accounts.WalletEvent{Kind: accounts.WalletDropped}, account})
}
}
// Shut down the event collector and check events.
sub.Unsubscribe()
<-updates
checkAccounts(t, live, ks.Wallets())
checkEvents(t, wantEvents, events)
}
// checkAccounts checks that all known live accounts are present in the wallet list.
func checkAccounts(t *testing.T, live map[common.Address]accounts.Account, wallets []accounts.Wallet) {
if len(live) != len(wallets) {
t.Errorf("wallet list doesn't match required accounts: have %d, want %d", len(wallets), len(live))
return
}
liveList := make([]accounts.Account, 0, len(live))
for _, account := range live {
liveList = append(liveList, account)
}
sort.Sort(accountsByURL(liveList))
for j, wallet := range wallets {
if accs := wallet.Accounts(); len(accs) != 1 {
t.Errorf("wallet %d: contains invalid number of accounts: have %d, want 1", j, len(accs))
} else if accs[0] != liveList[j] {
t.Errorf("wallet %d: account mismatch: have %v, want %v", j, accs[0], liveList[j])
}
}
}
// checkEvents checks that all events in 'want' are present in 'have'. Events may be present multiple times.
func checkEvents(t *testing.T, want []walletEvent, have []walletEvent) {
for _, wantEv := range want {
nmatch := 0
for ; len(have) > 0; nmatch++ {
if have[0].Kind != wantEv.Kind || have[0].a != wantEv.a {
break
}
have = have[1:]
}
if nmatch == 0 {
t.Fatalf("can't find event with Kind=%v for %x", wantEv.Kind, wantEv.a.Address)
}
}
}
func tmpKeyStore(t *testing.T, encrypted bool) (string, *KeyStore) {
d, err := ioutil.TempDir("", "eth-keystore-test")
if err != nil {
t.Fatal(err)
}
new := NewPlaintextKeyStore
if encrypted {
new = func(kd string) *KeyStore { return NewKeyStore(kd, veryLightScryptN, veryLightScryptP) }
}
return d, new(d)
}

View File

@@ -0,0 +1,139 @@
// Copyright 2017 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 keystore
import (
"math/big"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/core/types"
)
// keystoreWallet implements the accounts.Wallet interface for the original
// keystore.
type keystoreWallet struct {
account accounts.Account // Single account contained in this wallet
keystore *KeyStore // Keystore where the account originates from
}
// URL implements accounts.Wallet, returning the URL of the account within.
func (w *keystoreWallet) URL() accounts.URL {
return w.account.URL
}
// Status implements accounts.Wallet, returning whether the account held by the
// keystore wallet is unlocked or not.
func (w *keystoreWallet) Status() (string, error) {
w.keystore.mu.RLock()
defer w.keystore.mu.RUnlock()
if _, ok := w.keystore.unlocked[w.account.Address]; ok {
return "Unlocked", nil
}
return "Locked", nil
}
// Open implements accounts.Wallet, but is a noop for plain wallets since there
// is no connection or decryption step necessary to access the list of accounts.
func (w *keystoreWallet) Open(passphrase string) error { return nil }
// Close implements accounts.Wallet, but is a noop for plain wallets since is no
// meaningful open operation.
func (w *keystoreWallet) Close() error { return nil }
// Accounts implements accounts.Wallet, returning an account list consisting of
// a single account that the plain kestore wallet contains.
func (w *keystoreWallet) Accounts() []accounts.Account {
return []accounts.Account{w.account}
}
// Contains implements accounts.Wallet, returning whether a particular account is
// or is not wrapped by this wallet instance.
func (w *keystoreWallet) Contains(account accounts.Account) bool {
return account.Address == w.account.Address && (account.URL == (accounts.URL{}) || account.URL == w.account.URL)
}
// Derive implements accounts.Wallet, but is a noop for plain wallets since there
// is no notion of hierarchical account derivation for plain keystore accounts.
func (w *keystoreWallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
return accounts.Account{}, accounts.ErrNotSupported
}
// SelfDerive implements accounts.Wallet, but is a noop for plain wallets since
// there is no notion of hierarchical account derivation for plain keystore accounts.
func (w *keystoreWallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) {}
// SignHash implements accounts.Wallet, attempting to sign the given hash with
// the given account. If the wallet does not wrap this particular account, an
// error is returned to avoid account leakage (even though in theory we may be
// able to sign via our shared keystore backend).
func (w *keystoreWallet) SignHash(account accounts.Account, hash []byte) ([]byte, error) {
// Make sure the requested account is contained within
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
}
if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
return w.keystore.SignHash(account, hash)
}
// SignTx implements accounts.Wallet, attempting to sign the given transaction
// with the given account. If the wallet does not wrap this particular account,
// an error is returned to avoid account leakage (even though in theory we may
// be able to sign via our shared keystore backend).
func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
// Make sure the requested account is contained within
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
}
if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
return w.keystore.SignTx(account, tx, chainID)
}
// SignHashWithPassphrase implements accounts.Wallet, attempting to sign the
// given hash with the given account using passphrase as extra authentication.
func (w *keystoreWallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) {
// Make sure the requested account is contained within
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
}
if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
return w.keystore.SignHashWithPassphrase(account, passphrase, hash)
}
// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
// transaction with the given account using passphrase as extra authentication.
func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
// Make sure the requested account is contained within
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
}
if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
return w.keystore.SignTxWithPassphrase(account, passphrase, tx, chainID)
}

View File

@@ -14,7 +14,7 @@
// 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 accounts
package keystore
import (
"crypto/aes"
@@ -22,22 +22,24 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/crypto"
"github.com/pborman/uuid"
"golang.org/x/crypto/pbkdf2"
)
// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (Account, *Key, error) {
func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (accounts.Account, *Key, error) {
key, err := decryptPreSaleKey(keyJSON, password)
if err != nil {
return Account{}, nil, err
return accounts.Account{}, nil, err
}
key.Id = uuid.NewRandom()
a := Account{Address: key.Address, File: keyStore.JoinPath(keyFileName(key.Address))}
err = keyStore.StoreKey(a.File, key, password)
a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: keyStore.JoinPath(keyFileName(key.Address))}}
err = keyStore.StoreKey(a.URL.Path, key, password)
return a, key, err
}
@@ -53,6 +55,12 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
return nil, err
}
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
if err != nil {
return nil, errors.New("invalid hex in encSeed")
}
if len(encSeedBytes) < 16 {
return nil, errors.New("invalid encSeed, too short")
}
iv := encSeedBytes[:16]
cipherText := encSeedBytes[16:]
/*
@@ -69,7 +77,8 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
return nil, err
}
ethPriv := crypto.Keccak256(plainText)
ecKey := crypto.ToECDSA(ethPriv)
ecKey := crypto.ToECDSAUnsafe(ethPriv)
key = &Key{
Id: nil,
Address: crypto.PubkeyToAddress(ecKey.PublicKey),

108
accounts/keystore/watch.go Normal file
View File

@@ -0,0 +1,108 @@
// Copyright 2016 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 darwin,!ios freebsd linux,!arm64 netbsd solaris
package keystore
import (
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/rjeczalik/notify"
)
type watcher struct {
ac *accountCache
starting bool
running bool
ev chan notify.EventInfo
quit chan struct{}
}
func newWatcher(ac *accountCache) *watcher {
return &watcher{
ac: ac,
ev: make(chan notify.EventInfo, 10),
quit: make(chan struct{}),
}
}
// starts the watcher loop in the background.
// Start a watcher in the background if that's not already in progress.
// The caller must hold w.ac.mu.
func (w *watcher) start() {
if w.starting || w.running {
return
}
w.starting = true
go w.loop()
}
func (w *watcher) close() {
close(w.quit)
}
func (w *watcher) loop() {
defer func() {
w.ac.mu.Lock()
w.running = false
w.starting = false
w.ac.mu.Unlock()
}()
logger := log.New("path", w.ac.keydir)
if err := notify.Watch(w.ac.keydir, w.ev, notify.All); err != nil {
logger.Trace("Failed to watch keystore folder", "err", err)
return
}
defer notify.Stop(w.ev)
logger.Trace("Started watching keystore folder")
defer logger.Trace("Stopped watching keystore folder")
w.ac.mu.Lock()
w.running = true
w.ac.mu.Unlock()
// Wait for file system events and reload.
// When an event occurs, the reload call is delayed a bit so that
// multiple events arriving quickly only cause a single reload.
var (
debounceDuration = 500 * time.Millisecond
rescanTriggered = false
debounce = time.NewTimer(0)
)
// Ignore initial trigger
if !debounce.Stop() {
<-debounce.C
}
defer debounce.Stop()
for {
select {
case <-w.quit:
return
case <-w.ev:
// Trigger the scan (with delay), if not already triggered
if !rescanTriggered {
debounce.Reset(debounceDuration)
rescanTriggered = true
}
case <-debounce.C:
w.ac.scanAccounts()
rescanTriggered = false
}
}
}

View File

@@ -14,15 +14,15 @@
// 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 ios linux,arm64 !darwin,!freebsd,!linux,!netbsd,!solaris,!windows
// +build ios linux,arm64 windows !darwin,!freebsd,!linux,!netbsd,!solaris
// This is the fallback implementation of directory watching.
// It is used on unsupported platforms.
package accounts
package keystore
type watcher struct{ running bool }
func newWatcher(*addrCache) *watcher { return new(watcher) }
func (*watcher) start() {}
func (*watcher) close() {}
func newWatcher(*accountCache) *watcher { return new(watcher) }
func (*watcher) start() {}
func (*watcher) close() {}

199
accounts/manager.go Normal file
View File

@@ -0,0 +1,199 @@
// Copyright 2017 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 accounts
import (
"reflect"
"sort"
"sync"
"github.com/ethereum/go-ethereum/event"
)
// Manager is an overarching account manager that can communicate with various
// backends for signing transactions.
type Manager struct {
backends map[reflect.Type][]Backend // Index of backends currently registered
updaters []event.Subscription // Wallet update subscriptions for all backends
updates chan WalletEvent // Subscription sink for backend wallet changes
wallets []Wallet // Cache of all wallets from all registered backends
feed event.Feed // Wallet feed notifying of arrivals/departures
quit chan chan error
lock sync.RWMutex
}
// NewManager creates a generic account manager to sign transaction via various
// supported backends.
func NewManager(backends ...Backend) *Manager {
// Retrieve the initial list of wallets from the backends and sort by URL
var wallets []Wallet
for _, backend := range backends {
wallets = merge(wallets, backend.Wallets()...)
}
// Subscribe to wallet notifications from all backends
updates := make(chan WalletEvent, 4*len(backends))
subs := make([]event.Subscription, len(backends))
for i, backend := range backends {
subs[i] = backend.Subscribe(updates)
}
// Assemble the account manager and return
am := &Manager{
backends: make(map[reflect.Type][]Backend),
updaters: subs,
updates: updates,
wallets: wallets,
quit: make(chan chan error),
}
for _, backend := range backends {
kind := reflect.TypeOf(backend)
am.backends[kind] = append(am.backends[kind], backend)
}
go am.update()
return am
}
// Close terminates the account manager's internal notification processes.
func (am *Manager) Close() error {
errc := make(chan error)
am.quit <- errc
return <-errc
}
// update is the wallet event loop listening for notifications from the backends
// and updating the cache of wallets.
func (am *Manager) update() {
// Close all subscriptions when the manager terminates
defer func() {
am.lock.Lock()
for _, sub := range am.updaters {
sub.Unsubscribe()
}
am.updaters = nil
am.lock.Unlock()
}()
// Loop until termination
for {
select {
case event := <-am.updates:
// Wallet event arrived, update local cache
am.lock.Lock()
switch event.Kind {
case WalletArrived:
am.wallets = merge(am.wallets, event.Wallet)
case WalletDropped:
am.wallets = drop(am.wallets, event.Wallet)
}
am.lock.Unlock()
// Notify any listeners of the event
am.feed.Send(event)
case errc := <-am.quit:
// Manager terminating, return
errc <- nil
return
}
}
}
// Backends retrieves the backend(s) with the given type from the account manager.
func (am *Manager) Backends(kind reflect.Type) []Backend {
return am.backends[kind]
}
// Wallets returns all signer accounts registered under this account manager.
func (am *Manager) Wallets() []Wallet {
am.lock.RLock()
defer am.lock.RUnlock()
cpy := make([]Wallet, len(am.wallets))
copy(cpy, am.wallets)
return cpy
}
// Wallet retrieves the wallet associated with a particular URL.
func (am *Manager) Wallet(url string) (Wallet, error) {
am.lock.RLock()
defer am.lock.RUnlock()
parsed, err := parseURL(url)
if err != nil {
return nil, err
}
for _, wallet := range am.Wallets() {
if wallet.URL() == parsed {
return wallet, nil
}
}
return nil, ErrUnknownWallet
}
// Find attempts to locate the wallet corresponding to a specific account. Since
// accounts can be dynamically added to and removed from wallets, this method has
// a linear runtime in the number of wallets.
func (am *Manager) Find(account Account) (Wallet, error) {
am.lock.RLock()
defer am.lock.RUnlock()
for _, wallet := range am.wallets {
if wallet.Contains(account) {
return wallet, nil
}
}
return nil, ErrUnknownAccount
}
// Subscribe creates an async subscription to receive notifications when the
// manager detects the arrival or departure of a wallet from any of its backends.
func (am *Manager) Subscribe(sink chan<- WalletEvent) event.Subscription {
return am.feed.Subscribe(sink)
}
// merge is a sorted analogue of append for wallets, where the ordering of the
// origin list is preserved by inserting new wallets at the correct position.
//
// The original slice is assumed to be already sorted by URL.
func merge(slice []Wallet, wallets ...Wallet) []Wallet {
for _, wallet := range wallets {
n := sort.Search(len(slice), func(i int) bool { return slice[i].URL().Cmp(wallet.URL()) >= 0 })
if n == len(slice) {
slice = append(slice, wallet)
continue
}
slice = append(slice[:n], append([]Wallet{wallet}, slice[n:]...)...)
}
return slice
}
// drop is the couterpart of merge, which looks up wallets from within the sorted
// cache and removes the ones specified.
func drop(slice []Wallet, wallets ...Wallet) []Wallet {
for _, wallet := range wallets {
n := sort.Search(len(slice), func(i int) bool { return slice[i].URL().Cmp(wallet.URL()) >= 0 })
if n == len(slice) {
// Wallet not found, may happen during startup
continue
}
slice = append(slice[:n], slice[n+1:]...)
}
return slice
}

88
accounts/url.go Normal file
View File

@@ -0,0 +1,88 @@
// Copyright 2017 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 accounts
import (
"encoding/json"
"errors"
"fmt"
"strings"
)
// URL represents the canonical identification URL of a wallet or account.
//
// It is a simplified version of url.URL, with the important limitations (which
// are considered features here) that it contains value-copyable components only,
// as well as that it doesn't do any URL encoding/decoding of special characters.
//
// The former is important to allow an account to be copied without leaving live
// references to the original version, whereas the latter is important to ensure
// one single canonical form opposed to many allowed ones by the RFC 3986 spec.
//
// As such, these URLs should not be used outside of the scope of an Ethereum
// wallet or account.
type URL struct {
Scheme string // Protocol scheme to identify a capable account backend
Path string // Path for the backend to identify a unique entity
}
// parseURL converts a user supplied URL into the accounts specific structure.
func parseURL(url string) (URL, error) {
parts := strings.Split(url, "://")
if len(parts) != 2 || parts[0] == "" {
return URL{}, errors.New("protocol scheme missing")
}
return URL{
Scheme: parts[0],
Path: parts[1],
}, nil
}
// String implements the stringer interface.
func (u URL) String() string {
if u.Scheme != "" {
return fmt.Sprintf("%s://%s", u.Scheme, u.Path)
}
return u.Path
}
// TerminalString implements the log.TerminalStringer interface.
func (u URL) TerminalString() string {
url := u.String()
if len(url) > 32 {
return url[:31] + "…"
}
return url
}
// MarshalJSON implements the json.Marshaller interface.
func (u URL) MarshalJSON() ([]byte, error) {
return json.Marshal(u.String())
}
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
//
func (u URL) Cmp(url URL) int {
if u.Scheme == url.Scheme {
return strings.Compare(u.Path, url.Path)
}
return strings.Compare(u.Scheme, url.Scheme)
}

238
accounts/usbwallet/hub.go Normal file
View File

@@ -0,0 +1,238 @@
// Copyright 2017 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 usbwallet
import (
"errors"
"runtime"
"sync"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/karalabe/hid"
)
// LedgerScheme is the protocol scheme prefixing account and wallet URLs.
const LedgerScheme = "ledger"
// TrezorScheme is the protocol scheme prefixing account and wallet URLs.
const TrezorScheme = "trezor"
// refreshCycle is the maximum time between wallet refreshes (if USB hotplug
// notifications don't work).
const refreshCycle = time.Second
// refreshThrottling is the minimum time between wallet refreshes to avoid USB
// trashing.
const refreshThrottling = 500 * time.Millisecond
// Hub is a accounts.Backend that can find and handle generic USB hardware wallets.
type Hub struct {
scheme string // Protocol scheme prefixing account and wallet URLs.
vendorID uint16 // USB vendor identifier used for device discovery
productIDs []uint16 // USB product identifiers used for device discovery
usageID uint16 // USB usage page identifier used for macOS device discovery
endpointID int // USB endpoint identifier used for non-macOS device discovery
makeDriver func(log.Logger) driver // Factory method to construct a vendor specific driver
refreshed time.Time // Time instance when the list of wallets was last refreshed
wallets []accounts.Wallet // List of USB wallet devices currently tracking
updateFeed event.Feed // Event feed to notify wallet additions/removals
updateScope event.SubscriptionScope // Subscription scope tracking current live listeners
updating bool // Whether the event notification loop is running
quit chan chan error
stateLock sync.RWMutex // Protects the internals of the hub from racey access
// TODO(karalabe): remove if hotplug lands on Windows
commsPend int // Number of operations blocking enumeration
commsLock sync.Mutex // Lock protecting the pending counter and enumeration
}
// NewLedgerHub creates a new hardware wallet manager for Ledger devices.
func NewLedgerHub() (*Hub, error) {
return newHub(LedgerScheme, 0x2c97, []uint16{0x0000 /* Ledger Blue */, 0x0001 /* Ledger Nano S */}, 0xffa0, 0, newLedgerDriver)
}
// NewTrezorHub creates a new hardware wallet manager for Trezor devices.
func NewTrezorHub() (*Hub, error) {
return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor 1 */}, 0xff00, 0, newTrezorDriver)
}
// newHub creates a new hardware wallet manager for generic USB devices.
func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) {
if !hid.Supported() {
return nil, errors.New("unsupported platform")
}
hub := &Hub{
scheme: scheme,
vendorID: vendorID,
productIDs: productIDs,
usageID: usageID,
endpointID: endpointID,
makeDriver: makeDriver,
quit: make(chan chan error),
}
hub.refreshWallets()
return hub, nil
}
// Wallets implements accounts.Backend, returning all the currently tracked USB
// devices that appear to be hardware wallets.
func (hub *Hub) Wallets() []accounts.Wallet {
// Make sure the list of wallets is up to date
hub.refreshWallets()
hub.stateLock.RLock()
defer hub.stateLock.RUnlock()
cpy := make([]accounts.Wallet, len(hub.wallets))
copy(cpy, hub.wallets)
return cpy
}
// refreshWallets scans the USB devices attached to the machine and updates the
// list of wallets based on the found devices.
func (hub *Hub) refreshWallets() {
// Don't scan the USB like crazy it the user fetches wallets in a loop
hub.stateLock.RLock()
elapsed := time.Since(hub.refreshed)
hub.stateLock.RUnlock()
if elapsed < refreshThrottling {
return
}
// Retrieve the current list of USB wallet devices
var devices []hid.DeviceInfo
if runtime.GOOS == "linux" {
// hidapi on Linux opens the device during enumeration to retrieve some infos,
// breaking the Ledger protocol if that is waiting for user confirmation. This
// is a bug acknowledged at Ledger, but it won't be fixed on old devices so we
// need to prevent concurrent comms ourselves. The more elegant solution would
// be to ditch enumeration in favor of hutplug events, but that don't work yet
// on Windows so if we need to hack it anyway, this is more elegant for now.
hub.commsLock.Lock()
if hub.commsPend > 0 { // A confirmation is pending, don't refresh
hub.commsLock.Unlock()
return
}
}
for _, info := range hid.Enumerate(hub.vendorID, 0) {
for _, id := range hub.productIDs {
if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) {
devices = append(devices, info)
break
}
}
}
if runtime.GOOS == "linux" {
// See rationale before the enumeration why this is needed and only on Linux.
hub.commsLock.Unlock()
}
// Transform the current list of wallets into the new one
hub.stateLock.Lock()
wallets := make([]accounts.Wallet, 0, len(devices))
events := []accounts.WalletEvent{}
for _, device := range devices {
url := accounts.URL{Scheme: hub.scheme, Path: device.Path}
// Drop wallets in front of the next device or those that failed for some reason
for len(hub.wallets) > 0 {
// Abort if we're past the current device and found an operational one
_, failure := hub.wallets[0].Status()
if hub.wallets[0].URL().Cmp(url) >= 0 || failure == nil {
break
}
// Drop the stale and failed devices
events = append(events, accounts.WalletEvent{Wallet: hub.wallets[0], Kind: accounts.WalletDropped})
hub.wallets = hub.wallets[1:]
}
// If there are no more wallets or the device is before the next, wrap new wallet
if len(hub.wallets) == 0 || hub.wallets[0].URL().Cmp(url) > 0 {
logger := log.New("url", url)
wallet := &wallet{hub: hub, driver: hub.makeDriver(logger), url: &url, info: device, log: logger}
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived})
wallets = append(wallets, wallet)
continue
}
// If the device is the same as the first wallet, keep it
if hub.wallets[0].URL().Cmp(url) == 0 {
wallets = append(wallets, hub.wallets[0])
hub.wallets = hub.wallets[1:]
continue
}
}
// Drop any leftover wallets and set the new batch
for _, wallet := range hub.wallets {
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletDropped})
}
hub.refreshed = time.Now()
hub.wallets = wallets
hub.stateLock.Unlock()
// Fire all wallet events and return
for _, event := range events {
hub.updateFeed.Send(event)
}
}
// Subscribe implements accounts.Backend, creating an async subscription to
// receive notifications on the addition or removal of USB wallets.
func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription {
// We need the mutex to reliably start/stop the update loop
hub.stateLock.Lock()
defer hub.stateLock.Unlock()
// Subscribe the caller and track the subscriber count
sub := hub.updateScope.Track(hub.updateFeed.Subscribe(sink))
// Subscribers require an active notification loop, start it
if !hub.updating {
hub.updating = true
go hub.updater()
}
return sub
}
// updater is responsible for maintaining an up-to-date list of wallets managed
// by the USB hub, and for firing wallet addition/removal events.
func (hub *Hub) updater() {
for {
// TODO: Wait for a USB hotplug event (not supported yet) or a refresh timeout
// <-hub.changes
time.Sleep(refreshCycle)
// Run the wallet refresher
hub.refreshWallets()
// If all our subscribers left, stop the updater
hub.stateLock.Lock()
if hub.updateScope.Count() == 0 {
hub.updating = false
hub.stateLock.Unlock()
return
}
hub.stateLock.Unlock()
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,905 @@
// This file originates from the SatoshiLabs Trezor `common` repository at:
// https://github.com/trezor/trezor-common/blob/master/protob/messages.proto
// dated 28.07.2017, commit dd8ec3231fb5f7992360aff9bdfe30bb58130f4b.
syntax = "proto2";
/**
* Messages for TREZOR communication
*/
// Sugar for easier handling in Java
option java_package = "com.satoshilabs.trezor.lib.protobuf";
option java_outer_classname = "TrezorMessage";
import "types.proto";
/**
* Mapping between Trezor wire identifier (uint) and a protobuf message
*/
enum MessageType {
MessageType_Initialize = 0 [(wire_in) = true];
MessageType_Ping = 1 [(wire_in) = true];
MessageType_Success = 2 [(wire_out) = true];
MessageType_Failure = 3 [(wire_out) = true];
MessageType_ChangePin = 4 [(wire_in) = true];
MessageType_WipeDevice = 5 [(wire_in) = true];
MessageType_FirmwareErase = 6 [(wire_in) = true, (wire_bootloader) = true];
MessageType_FirmwareUpload = 7 [(wire_in) = true, (wire_bootloader) = true];
MessageType_FirmwareRequest = 8 [(wire_out) = true, (wire_bootloader) = true];
MessageType_GetEntropy = 9 [(wire_in) = true];
MessageType_Entropy = 10 [(wire_out) = true];
MessageType_GetPublicKey = 11 [(wire_in) = true];
MessageType_PublicKey = 12 [(wire_out) = true];
MessageType_LoadDevice = 13 [(wire_in) = true];
MessageType_ResetDevice = 14 [(wire_in) = true];
MessageType_SignTx = 15 [(wire_in) = true];
MessageType_SimpleSignTx = 16 [(wire_in) = true, deprecated = true];
MessageType_Features = 17 [(wire_out) = true];
MessageType_PinMatrixRequest = 18 [(wire_out) = true];
MessageType_PinMatrixAck = 19 [(wire_in) = true, (wire_tiny) = true];
MessageType_Cancel = 20 [(wire_in) = true];
MessageType_TxRequest = 21 [(wire_out) = true];
MessageType_TxAck = 22 [(wire_in) = true];
MessageType_CipherKeyValue = 23 [(wire_in) = true];
MessageType_ClearSession = 24 [(wire_in) = true];
MessageType_ApplySettings = 25 [(wire_in) = true];
MessageType_ButtonRequest = 26 [(wire_out) = true];
MessageType_ButtonAck = 27 [(wire_in) = true, (wire_tiny) = true];
MessageType_ApplyFlags = 28 [(wire_in) = true];
MessageType_GetAddress = 29 [(wire_in) = true];
MessageType_Address = 30 [(wire_out) = true];
MessageType_SelfTest = 32 [(wire_in) = true, (wire_bootloader) = true];
MessageType_BackupDevice = 34 [(wire_in) = true];
MessageType_EntropyRequest = 35 [(wire_out) = true];
MessageType_EntropyAck = 36 [(wire_in) = true];
MessageType_SignMessage = 38 [(wire_in) = true];
MessageType_VerifyMessage = 39 [(wire_in) = true];
MessageType_MessageSignature = 40 [(wire_out) = true];
MessageType_PassphraseRequest = 41 [(wire_out) = true];
MessageType_PassphraseAck = 42 [(wire_in) = true, (wire_tiny) = true];
MessageType_EstimateTxSize = 43 [(wire_in) = true, deprecated = true];
MessageType_TxSize = 44 [(wire_out) = true, deprecated = true];
MessageType_RecoveryDevice = 45 [(wire_in) = true];
MessageType_WordRequest = 46 [(wire_out) = true];
MessageType_WordAck = 47 [(wire_in) = true];
MessageType_CipheredKeyValue = 48 [(wire_out) = true];
MessageType_EncryptMessage = 49 [(wire_in) = true, deprecated = true];
MessageType_EncryptedMessage = 50 [(wire_out) = true, deprecated = true];
MessageType_DecryptMessage = 51 [(wire_in) = true, deprecated = true];
MessageType_DecryptedMessage = 52 [(wire_out) = true, deprecated = true];
MessageType_SignIdentity = 53 [(wire_in) = true];
MessageType_SignedIdentity = 54 [(wire_out) = true];
MessageType_GetFeatures = 55 [(wire_in) = true];
MessageType_EthereumGetAddress = 56 [(wire_in) = true];
MessageType_EthereumAddress = 57 [(wire_out) = true];
MessageType_EthereumSignTx = 58 [(wire_in) = true];
MessageType_EthereumTxRequest = 59 [(wire_out) = true];
MessageType_EthereumTxAck = 60 [(wire_in) = true];
MessageType_GetECDHSessionKey = 61 [(wire_in) = true];
MessageType_ECDHSessionKey = 62 [(wire_out) = true];
MessageType_SetU2FCounter = 63 [(wire_in) = true];
MessageType_EthereumSignMessage = 64 [(wire_in) = true];
MessageType_EthereumVerifyMessage = 65 [(wire_in) = true];
MessageType_EthereumMessageSignature = 66 [(wire_out) = true];
MessageType_DebugLinkDecision = 100 [(wire_debug_in) = true, (wire_tiny) = true];
MessageType_DebugLinkGetState = 101 [(wire_debug_in) = true];
MessageType_DebugLinkState = 102 [(wire_debug_out) = true];
MessageType_DebugLinkStop = 103 [(wire_debug_in) = true];
MessageType_DebugLinkLog = 104 [(wire_debug_out) = true];
MessageType_DebugLinkMemoryRead = 110 [(wire_debug_in) = true];
MessageType_DebugLinkMemory = 111 [(wire_debug_out) = true];
MessageType_DebugLinkMemoryWrite = 112 [(wire_debug_in) = true];
MessageType_DebugLinkFlashErase = 113 [(wire_debug_in) = true];
}
////////////////////
// Basic messages //
////////////////////
/**
* Request: Reset device to default state and ask for device details
* @next Features
*/
message Initialize {
}
/**
* Request: Ask for device details (no device reset)
* @next Features
*/
message GetFeatures {
}
/**
* Response: Reports various information about the device
* @prev Initialize
* @prev GetFeatures
*/
message Features {
optional string vendor = 1; // name of the manufacturer, e.g. "bitcointrezor.com"
optional uint32 major_version = 2; // major version of the device, e.g. 1
optional uint32 minor_version = 3; // minor version of the device, e.g. 0
optional uint32 patch_version = 4; // patch version of the device, e.g. 0
optional bool bootloader_mode = 5; // is device in bootloader mode?
optional string device_id = 6; // device's unique identifier
optional bool pin_protection = 7; // is device protected by PIN?
optional bool passphrase_protection = 8; // is node/mnemonic encrypted using passphrase?
optional string language = 9; // device language
optional string label = 10; // device description label
repeated CoinType coins = 11; // supported coins
optional bool initialized = 12; // does device contain seed?
optional bytes revision = 13; // SCM revision of firmware
optional bytes bootloader_hash = 14; // hash of the bootloader
optional bool imported = 15; // was storage imported from an external source?
optional bool pin_cached = 16; // is PIN already cached in session?
optional bool passphrase_cached = 17; // is passphrase already cached in session?
optional bool firmware_present = 18; // is valid firmware loaded?
optional bool needs_backup = 19; // does storage need backup? (equals to Storage.needs_backup)
optional uint32 flags = 20; // device flags (equals to Storage.flags)
}
/**
* Request: clear session (removes cached PIN, passphrase, etc).
* @next Success
*/
message ClearSession {
}
/**
* Request: change language and/or label of the device
* @next Success
* @next Failure
* @next ButtonRequest
* @next PinMatrixRequest
*/
message ApplySettings {
optional string language = 1;
optional string label = 2;
optional bool use_passphrase = 3;
optional bytes homescreen = 4;
}
/**
* Request: set flags of the device
* @next Success
* @next Failure
*/
message ApplyFlags {
optional uint32 flags = 1; // bitmask, can only set bits, not unset
}
/**
* Request: Starts workflow for setting/changing/removing the PIN
* @next ButtonRequest
* @next PinMatrixRequest
*/
message ChangePin {
optional bool remove = 1; // is PIN removal requested?
}
/**
* Request: Test if the device is alive, device sends back the message in Success response
* @next Success
*/
message Ping {
optional string message = 1; // message to send back in Success message
optional bool button_protection = 2; // ask for button press
optional bool pin_protection = 3; // ask for PIN if set in device
optional bool passphrase_protection = 4; // ask for passphrase if set in device
}
/**
* Response: Success of the previous request
*/
message Success {
optional string message = 1; // human readable description of action or request-specific payload
}
/**
* Response: Failure of the previous request
*/
message Failure {
optional FailureType code = 1; // computer-readable definition of the error state
optional string message = 2; // human-readable message of the error state
}
/**
* Response: Device is waiting for HW button press.
* @next ButtonAck
* @next Cancel
*/
message ButtonRequest {
optional ButtonRequestType code = 1;
optional string data = 2;
}
/**
* Request: Computer agrees to wait for HW button press
* @prev ButtonRequest
*/
message ButtonAck {
}
/**
* Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme
* @next PinMatrixAck
* @next Cancel
*/
message PinMatrixRequest {
optional PinMatrixRequestType type = 1;
}
/**
* Request: Computer responds with encoded PIN
* @prev PinMatrixRequest
*/
message PinMatrixAck {
required string pin = 1; // matrix encoded PIN entered by user
}
/**
* Request: Abort last operation that required user interaction
* @prev ButtonRequest
* @prev PinMatrixRequest
* @prev PassphraseRequest
*/
message Cancel {
}
/**
* Response: Device awaits encryption passphrase
* @next PassphraseAck
* @next Cancel
*/
message PassphraseRequest {
}
/**
* Request: Send passphrase back
* @prev PassphraseRequest
*/
message PassphraseAck {
required string passphrase = 1;
}
/**
* Request: Request a sample of random data generated by hardware RNG. May be used for testing.
* @next ButtonRequest
* @next Entropy
* @next Failure
*/
message GetEntropy {
required uint32 size = 1; // size of requested entropy
}
/**
* Response: Reply with random data generated by internal RNG
* @prev GetEntropy
*/
message Entropy {
required bytes entropy = 1; // stream of random generated bytes
}
/**
* Request: Ask device for public key corresponding to address_n path
* @next PassphraseRequest
* @next PublicKey
* @next Failure
*/
message GetPublicKey {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
optional string ecdsa_curve_name = 2; // ECDSA curve name to use
optional bool show_display = 3; // optionally show on display before sending the result
optional string coin_name = 4 [default='Bitcoin'];
}
/**
* Response: Contains public key derived from device private seed
* @prev GetPublicKey
*/
message PublicKey {
required HDNodeType node = 1; // BIP32 public node
optional string xpub = 2; // serialized form of public node
}
/**
* Request: Ask device for address corresponding to address_n path
* @next PassphraseRequest
* @next Address
* @next Failure
*/
message GetAddress {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
optional string coin_name = 2 [default='Bitcoin'];
optional bool show_display = 3 ; // optionally show on display before sending the result
optional MultisigRedeemScriptType multisig = 4; // filled if we are showing a multisig address
optional InputScriptType script_type = 5 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.)
}
/**
* Request: Ask device for Ethereum address corresponding to address_n path
* @next PassphraseRequest
* @next EthereumAddress
* @next Failure
*/
message EthereumGetAddress {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
optional bool show_display = 2; // optionally show on display before sending the result
}
/**
* Response: Contains address derived from device private seed
* @prev GetAddress
*/
message Address {
required string address = 1; // Coin address in Base58 encoding
}
/**
* Response: Contains an Ethereum address derived from device private seed
* @prev EthereumGetAddress
*/
message EthereumAddress {
required bytes address = 1; // Coin address as an Ethereum 160 bit hash
}
/**
* Request: Request device to wipe all sensitive data and settings
* @next ButtonRequest
*/
message WipeDevice {
}
/**
* Request: Load seed and related internal settings from the computer
* @next ButtonRequest
* @next Success
* @next Failure
*/
message LoadDevice {
optional string mnemonic = 1; // seed encoded as BIP-39 mnemonic (12, 18 or 24 words)
optional HDNodeType node = 2; // BIP-32 node
optional string pin = 3; // set PIN protection
optional bool passphrase_protection = 4; // enable master node encryption using passphrase
optional string language = 5 [default='english']; // device language
optional string label = 6; // device label
optional bool skip_checksum = 7; // do not test mnemonic for valid BIP-39 checksum
optional uint32 u2f_counter = 8; // U2F counter
}
/**
* Request: Ask device to do initialization involving user interaction
* @next EntropyRequest
* @next Failure
*/
message ResetDevice {
optional bool display_random = 1; // display entropy generated by the device before asking for additional entropy
optional uint32 strength = 2 [default=256]; // strength of seed in bits
optional bool passphrase_protection = 3; // enable master node encryption using passphrase
optional bool pin_protection = 4; // enable PIN protection
optional string language = 5 [default='english']; // device language
optional string label = 6; // device label
optional uint32 u2f_counter = 7; // U2F counter
optional bool skip_backup = 8; // postpone seed backup to BackupDevice workflow
}
/**
* Request: Perform backup of the device seed if not backed up using ResetDevice
* @next ButtonRequest
*/
message BackupDevice {
}
/**
* Response: Ask for additional entropy from host computer
* @prev ResetDevice
* @next EntropyAck
*/
message EntropyRequest {
}
/**
* Request: Provide additional entropy for seed generation function
* @prev EntropyRequest
* @next ButtonRequest
*/
message EntropyAck {
optional bytes entropy = 1; // 256 bits (32 bytes) of random data
}
/**
* Request: Start recovery workflow asking user for specific words of mnemonic
* Used to recovery device safely even on untrusted computer.
* @next WordRequest
*/
message RecoveryDevice {
optional uint32 word_count = 1; // number of words in BIP-39 mnemonic
optional bool passphrase_protection = 2; // enable master node encryption using passphrase
optional bool pin_protection = 3; // enable PIN protection
optional string language = 4 [default='english']; // device language
optional string label = 5; // device label
optional bool enforce_wordlist = 6; // enforce BIP-39 wordlist during the process
// 7 reserved for unused recovery method
optional uint32 type = 8; // supported recovery type (see RecoveryType)
optional uint32 u2f_counter = 9; // U2F counter
optional bool dry_run = 10; // perform dry-run recovery workflow (for safe mnemonic validation)
}
/**
* Response: Device is waiting for user to enter word of the mnemonic
* Its position is shown only on device's internal display.
* @prev RecoveryDevice
* @prev WordAck
*/
message WordRequest {
optional WordRequestType type = 1;
}
/**
* Request: Computer replies with word from the mnemonic
* @prev WordRequest
* @next WordRequest
* @next Success
* @next Failure
*/
message WordAck {
required string word = 1; // one word of mnemonic on asked position
}
//////////////////////////////
// Message signing messages //
//////////////////////////////
/**
* Request: Ask device to sign message
* @next MessageSignature
* @next Failure
*/
message SignMessage {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
required bytes message = 2; // message to be signed
optional string coin_name = 3 [default='Bitcoin']; // coin to use for signing
optional InputScriptType script_type = 4 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.)
}
/**
* Request: Ask device to verify message
* @next Success
* @next Failure
*/
message VerifyMessage {
optional string address = 1; // address to verify
optional bytes signature = 2; // signature to verify
optional bytes message = 3; // message to verify
optional string coin_name = 4 [default='Bitcoin']; // coin to use for verifying
}
/**
* Response: Signed message
* @prev SignMessage
*/
message MessageSignature {
optional string address = 1; // address used to sign the message
optional bytes signature = 2; // signature of the message
}
///////////////////////////
// Encryption/decryption //
///////////////////////////
/**
* Request: Ask device to encrypt message
* @next EncryptedMessage
* @next Failure
*/
message EncryptMessage {
optional bytes pubkey = 1; // public key
optional bytes message = 2; // message to encrypt
optional bool display_only = 3; // show just on display? (don't send back via wire)
repeated uint32 address_n = 4; // BIP-32 path to derive the signing key from master node
optional string coin_name = 5 [default='Bitcoin']; // coin to use for signing
}
/**
* Response: Encrypted message
* @prev EncryptMessage
*/
message EncryptedMessage {
optional bytes nonce = 1; // nonce used during encryption
optional bytes message = 2; // encrypted message
optional bytes hmac = 3; // message hmac
}
/**
* Request: Ask device to decrypt message
* @next Success
* @next Failure
*/
message DecryptMessage {
repeated uint32 address_n = 1; // BIP-32 path to derive the decryption key from master node
optional bytes nonce = 2; // nonce used during encryption
optional bytes message = 3; // message to decrypt
optional bytes hmac = 4; // message hmac
}
/**
* Response: Decrypted message
* @prev DecryptedMessage
*/
message DecryptedMessage {
optional bytes message = 1; // decrypted message
optional string address = 2; // address used to sign the message (if used)
}
/**
* Request: Ask device to encrypt or decrypt value of given key
* @next CipheredKeyValue
* @next Failure
*/
message CipherKeyValue {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
optional string key = 2; // key component of key:value
optional bytes value = 3; // value component of key:value
optional bool encrypt = 4; // are we encrypting (True) or decrypting (False)?
optional bool ask_on_encrypt = 5; // should we ask on encrypt operation?
optional bool ask_on_decrypt = 6; // should we ask on decrypt operation?
optional bytes iv = 7; // initialization vector (will be computed if not set)
}
/**
* Response: Return ciphered/deciphered value
* @prev CipherKeyValue
*/
message CipheredKeyValue {
optional bytes value = 1; // ciphered/deciphered value
}
//////////////////////////////////
// Transaction signing messages //
//////////////////////////////////
/**
* Request: Estimated size of the transaction
* This behaves exactly like SignTx, which means that it can ask using TxRequest
* This call is non-blocking (except possible PassphraseRequest to unlock the seed)
* @next TxSize
* @next Failure
*/
message EstimateTxSize {
required uint32 outputs_count = 1; // number of transaction outputs
required uint32 inputs_count = 2; // number of transaction inputs
optional string coin_name = 3 [default='Bitcoin']; // coin to use
}
/**
* Response: Estimated size of the transaction
* @prev EstimateTxSize
*/
message TxSize {
optional uint32 tx_size = 1; // estimated size of transaction in bytes
}
/**
* Request: Ask device to sign transaction
* @next PassphraseRequest
* @next PinMatrixRequest
* @next TxRequest
* @next Failure
*/
message SignTx {
required uint32 outputs_count = 1; // number of transaction outputs
required uint32 inputs_count = 2; // number of transaction inputs
optional string coin_name = 3 [default='Bitcoin']; // coin to use
optional uint32 version = 4 [default=1]; // transaction version
optional uint32 lock_time = 5 [default=0]; // transaction lock_time
}
/**
* Request: Simplified transaction signing
* This method doesn't support streaming, so there are hardware limits in number of inputs and outputs.
* In case of success, the result is returned using TxRequest message.
* @next PassphraseRequest
* @next PinMatrixRequest
* @next TxRequest
* @next Failure
*/
message SimpleSignTx {
repeated TxInputType inputs = 1; // transaction inputs
repeated TxOutputType outputs = 2; // transaction outputs
repeated TransactionType transactions = 3; // transactions whose outputs are used to build current inputs
optional string coin_name = 4 [default='Bitcoin']; // coin to use
optional uint32 version = 5 [default=1]; // transaction version
optional uint32 lock_time = 6 [default=0]; // transaction lock_time
}
/**
* Response: Device asks for information for signing transaction or returns the last result
* If request_index is set, device awaits TxAck message (with fields filled in according to request_type)
* If signature_index is set, 'signature' contains signed input of signature_index's input
* @prev SignTx
* @prev SimpleSignTx
* @prev TxAck
*/
message TxRequest {
optional RequestType request_type = 1; // what should be filled in TxAck message?
optional TxRequestDetailsType details = 2; // request for tx details
optional TxRequestSerializedType serialized = 3; // serialized data and request for next
}
/**
* Request: Reported transaction data
* @prev TxRequest
* @next TxRequest
*/
message TxAck {
optional TransactionType tx = 1;
}
/**
* Request: Ask device to sign transaction
* All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing.
* Note: the first at most 1024 bytes of data MUST be transmitted as part of this message.
* @next PassphraseRequest
* @next PinMatrixRequest
* @next EthereumTxRequest
* @next Failure
*/
message EthereumSignTx {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
optional bytes nonce = 2; // <=256 bit unsigned big endian
optional bytes gas_price = 3; // <=256 bit unsigned big endian (in wei)
optional bytes gas_limit = 4; // <=256 bit unsigned big endian
optional bytes to = 5; // 160 bit address hash
optional bytes value = 6; // <=256 bit unsigned big endian (in wei)
optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes)
optional uint32 data_length = 8; // Length of transaction payload
optional uint32 chain_id = 9; // Chain Id for EIP 155
}
/**
* Response: Device asks for more data from transaction payload, or returns the signature.
* If data_length is set, device awaits that many more bytes of payload.
* Otherwise, the signature_* fields contain the computed transaction signature. All three fields will be present.
* @prev EthereumSignTx
* @next EthereumTxAck
*/
message EthereumTxRequest {
optional uint32 data_length = 1; // Number of bytes being requested (<= 1024)
optional uint32 signature_v = 2; // Computed signature (recovery parameter, limited to 27 or 28)
optional bytes signature_r = 3; // Computed signature R component (256 bit)
optional bytes signature_s = 4; // Computed signature S component (256 bit)
}
/**
* Request: Transaction payload data.
* @prev EthereumTxRequest
* @next EthereumTxRequest
*/
message EthereumTxAck {
optional bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes)
}
////////////////////////////////////////
// Ethereum: Message signing messages //
////////////////////////////////////////
/**
* Request: Ask device to sign message
* @next EthereumMessageSignature
* @next Failure
*/
message EthereumSignMessage {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
required bytes message = 2; // message to be signed
}
/**
* Request: Ask device to verify message
* @next Success
* @next Failure
*/
message EthereumVerifyMessage {
optional bytes address = 1; // address to verify
optional bytes signature = 2; // signature to verify
optional bytes message = 3; // message to verify
}
/**
* Response: Signed message
* @prev EthereumSignMessage
*/
message EthereumMessageSignature {
optional bytes address = 1; // address used to sign the message
optional bytes signature = 2; // signature of the message
}
///////////////////////
// Identity messages //
///////////////////////
/**
* Request: Ask device to sign identity
* @next SignedIdentity
* @next Failure
*/
message SignIdentity {
optional IdentityType identity = 1; // identity
optional bytes challenge_hidden = 2; // non-visible challenge
optional string challenge_visual = 3; // challenge shown on display (e.g. date+time)
optional string ecdsa_curve_name = 4; // ECDSA curve name to use
}
/**
* Response: Device provides signed identity
* @prev SignIdentity
*/
message SignedIdentity {
optional string address = 1; // identity address
optional bytes public_key = 2; // identity public key
optional bytes signature = 3; // signature of the identity data
}
///////////////////
// ECDH messages //
///////////////////
/**
* Request: Ask device to generate ECDH session key
* @next ECDHSessionKey
* @next Failure
*/
message GetECDHSessionKey {
optional IdentityType identity = 1; // identity
optional bytes peer_public_key = 2; // peer's public key
optional string ecdsa_curve_name = 3; // ECDSA curve name to use
}
/**
* Response: Device provides ECDH session key
* @prev GetECDHSessionKey
*/
message ECDHSessionKey {
optional bytes session_key = 1; // ECDH session key
}
///////////////////
// U2F messages //
///////////////////
/**
* Request: Set U2F counter
* @next Success
*/
message SetU2FCounter {
optional uint32 u2f_counter = 1; // counter
}
/////////////////////////
// Bootloader messages //
/////////////////////////
/**
* Request: Ask device to erase its firmware (so it can be replaced via FirmwareUpload)
* @next Success
* @next FirmwareRequest
* @next Failure
*/
message FirmwareErase {
optional uint32 length = 1; // length of new firmware
}
/**
* Response: Ask for firmware chunk
* @next FirmwareUpload
*/
message FirmwareRequest {
optional uint32 offset = 1; // offset of requested firmware chunk
optional uint32 length = 2; // length of requested firmware chunk
}
/**
* Request: Send firmware in binary form to the device
* @next Success
* @next Failure
*/
message FirmwareUpload {
required bytes payload = 1; // firmware to be loaded into device
optional bytes hash = 2; // hash of the payload
}
/**
* Request: Perform a device self-test
* @next Success
* @next Failure
*/
message SelfTest {
optional bytes payload = 1; // payload to be used in self-test
}
/////////////////////////////////////////////////////////////
// Debug messages (only available if DebugLink is enabled) //
/////////////////////////////////////////////////////////////
/**
* Request: "Press" the button on the device
* @next Success
*/
message DebugLinkDecision {
required bool yes_no = 1; // true for "Confirm", false for "Cancel"
}
/**
* Request: Computer asks for device state
* @next DebugLinkState
*/
message DebugLinkGetState {
}
/**
* Response: Device current state
* @prev DebugLinkGetState
*/
message DebugLinkState {
optional bytes layout = 1; // raw buffer of display
optional string pin = 2; // current PIN, blank if PIN is not set/enabled
optional string matrix = 3; // current PIN matrix
optional string mnemonic = 4; // current BIP-39 mnemonic
optional HDNodeType node = 5; // current BIP-32 node
optional bool passphrase_protection = 6; // is node/mnemonic encrypted using passphrase?
optional string reset_word = 7; // word on device display during ResetDevice workflow
optional bytes reset_entropy = 8; // current entropy during ResetDevice workflow
optional string recovery_fake_word = 9; // (fake) word on display during RecoveryDevice workflow
optional uint32 recovery_word_pos = 10; // index of mnemonic word the device is expecting during RecoveryDevice workflow
}
/**
* Request: Ask device to restart
*/
message DebugLinkStop {
}
/**
* Response: Device wants host to log event
*/
message DebugLinkLog {
optional uint32 level = 1;
optional string bucket = 2;
optional string text = 3;
}
/**
* Request: Read memory from device
* @next DebugLinkMemory
*/
message DebugLinkMemoryRead {
optional uint32 address = 1;
optional uint32 length = 2;
}
/**
* Response: Device sends memory back
* @prev DebugLinkMemoryRead
*/
message DebugLinkMemory {
optional bytes memory = 1;
}
/**
* Request: Write memory to device.
* WARNING: Writing to the wrong location can irreparably break the device.
*/
message DebugLinkMemoryWrite {
optional uint32 address = 1;
optional bytes memory = 2;
optional bool flash = 3;
}
/**
* Request: Erase block of flash on device
* WARNING: Writing to the wrong location can irreparably break the device.
*/
message DebugLinkFlashErase {
optional uint32 sector = 1;
}

View File

@@ -0,0 +1,46 @@
// Copyright 2017 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/>.
// This file contains the implementation for interacting with the Trezor hardware
// wallets. The wire protocol spec can be found on the SatoshiLabs website:
// https://doc.satoshilabs.com/trezor-tech/api-protobuf.html
//go:generate protoc --go_out=import_path=trezor:. types.proto messages.proto
// Package trezor contains the wire protocol wrapper in Go.
package trezor
import (
"reflect"
"github.com/golang/protobuf/proto"
)
// Type returns the protocol buffer type number of a specific message. If the
// message is nil, this method panics!
func Type(msg proto.Message) uint16 {
return uint16(MessageType_value["MessageType_"+reflect.TypeOf(msg).Elem().Name()])
}
// Name returns the friendly message type name of a specific protocol buffer
// type numbers.
func Name(kind uint16) string {
name := MessageType_name[int32(kind)]
if len(name) < 12 {
return name
}
return name[12:]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
// This file originates from the SatoshiLabs Trezor `common` repository at:
// https://github.com/trezor/trezor-common/blob/master/protob/types.proto
// dated 28.07.2017, commit dd8ec3231fb5f7992360aff9bdfe30bb58130f4b.
syntax = "proto2";
/**
* Types for TREZOR communication
*
* @author Marek Palatinus <slush@satoshilabs.com>
* @version 1.2
*/
// Sugar for easier handling in Java
option java_package = "com.satoshilabs.trezor.lib.protobuf";
option java_outer_classname = "TrezorType";
import "google/protobuf/descriptor.proto";
/**
* Options for specifying message direction and type of wire (normal/debug)
*/
extend google.protobuf.EnumValueOptions {
optional bool wire_in = 50002; // message can be transmitted via wire from PC to TREZOR
optional bool wire_out = 50003; // message can be transmitted via wire from TREZOR to PC
optional bool wire_debug_in = 50004; // message can be transmitted via debug wire from PC to TREZOR
optional bool wire_debug_out = 50005; // message can be transmitted via debug wire from TREZOR to PC
optional bool wire_tiny = 50006; // message is handled by TREZOR when the USB stack is in tiny mode
optional bool wire_bootloader = 50007; // message is only handled by TREZOR Bootloader
}
/**
* Type of failures returned by Failure message
* @used_in Failure
*/
enum FailureType {
Failure_UnexpectedMessage = 1;
Failure_ButtonExpected = 2;
Failure_DataError = 3;
Failure_ActionCancelled = 4;
Failure_PinExpected = 5;
Failure_PinCancelled = 6;
Failure_PinInvalid = 7;
Failure_InvalidSignature = 8;
Failure_ProcessError = 9;
Failure_NotEnoughFunds = 10;
Failure_NotInitialized = 11;
Failure_FirmwareError = 99;
}
/**
* Type of script which will be used for transaction output
* @used_in TxOutputType
*/
enum OutputScriptType {
PAYTOADDRESS = 0; // used for all addresses (bitcoin, p2sh, witness)
PAYTOSCRIPTHASH = 1; // p2sh address (deprecated; use PAYTOADDRESS)
PAYTOMULTISIG = 2; // only for change output
PAYTOOPRETURN = 3; // op_return
PAYTOWITNESS = 4; // only for change output
PAYTOP2SHWITNESS = 5; // only for change output
}
/**
* Type of script which will be used for transaction output
* @used_in TxInputType
*/
enum InputScriptType {
SPENDADDRESS = 0; // standard p2pkh address
SPENDMULTISIG = 1; // p2sh multisig address
EXTERNAL = 2; // reserved for external inputs (coinjoin)
SPENDWITNESS = 3; // native segwit
SPENDP2SHWITNESS = 4; // segwit over p2sh (backward compatible)
}
/**
* Type of information required by transaction signing process
* @used_in TxRequest
*/
enum RequestType {
TXINPUT = 0;
TXOUTPUT = 1;
TXMETA = 2;
TXFINISHED = 3;
TXEXTRADATA = 4;
}
/**
* Type of button request
* @used_in ButtonRequest
*/
enum ButtonRequestType {
ButtonRequest_Other = 1;
ButtonRequest_FeeOverThreshold = 2;
ButtonRequest_ConfirmOutput = 3;
ButtonRequest_ResetDevice = 4;
ButtonRequest_ConfirmWord = 5;
ButtonRequest_WipeDevice = 6;
ButtonRequest_ProtectCall = 7;
ButtonRequest_SignTx = 8;
ButtonRequest_FirmwareCheck = 9;
ButtonRequest_Address = 10;
ButtonRequest_PublicKey = 11;
}
/**
* Type of PIN request
* @used_in PinMatrixRequest
*/
enum PinMatrixRequestType {
PinMatrixRequestType_Current = 1;
PinMatrixRequestType_NewFirst = 2;
PinMatrixRequestType_NewSecond = 3;
}
/**
* Type of recovery procedure. These should be used as bitmask, e.g.,
* `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix`
* listing every method supported by the host computer.
*
* Note that ScrambledWords must be supported by every implementation
* for backward compatibility; there is no way to not support it.
*
* @used_in RecoveryDevice
*/
enum RecoveryDeviceType {
// use powers of two when extending this field
RecoveryDeviceType_ScrambledWords = 0; // words in scrambled order
RecoveryDeviceType_Matrix = 1; // matrix recovery type
}
/**
* Type of Recovery Word request
* @used_in WordRequest
*/
enum WordRequestType {
WordRequestType_Plain = 0;
WordRequestType_Matrix9 = 1;
WordRequestType_Matrix6 = 2;
}
/**
* Structure representing BIP32 (hierarchical deterministic) node
* Used for imports of private key into the device and exporting public key out of device
* @used_in PublicKey
* @used_in LoadDevice
* @used_in DebugLinkState
* @used_in Storage
*/
message HDNodeType {
required uint32 depth = 1;
required uint32 fingerprint = 2;
required uint32 child_num = 3;
required bytes chain_code = 4;
optional bytes private_key = 5;
optional bytes public_key = 6;
}
message HDNodePathType {
required HDNodeType node = 1; // BIP-32 node in deserialized form
repeated uint32 address_n = 2; // BIP-32 path to derive the key from node
}
/**
* Structure representing Coin
* @used_in Features
*/
message CoinType {
optional string coin_name = 1;
optional string coin_shortcut = 2;
optional uint32 address_type = 3 [default=0];
optional uint64 maxfee_kb = 4;
optional uint32 address_type_p2sh = 5 [default=5];
optional string signed_message_header = 8;
optional uint32 xpub_magic = 9 [default=76067358]; // default=0x0488b21e
optional uint32 xprv_magic = 10 [default=76066276]; // default=0x0488ade4
optional bool segwit = 11;
optional uint32 forkid = 12;
}
/**
* Type of redeem script used in input
* @used_in TxInputType
*/
message MultisigRedeemScriptType {
repeated HDNodePathType pubkeys = 1; // pubkeys from multisig address (sorted lexicographically)
repeated bytes signatures = 2; // existing signatures for partially signed input
optional uint32 m = 3; // "m" from n, how many valid signatures is necessary for spending
}
/**
* Structure representing transaction input
* @used_in SimpleSignTx
* @used_in TransactionType
*/
message TxInputType {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
required bytes prev_hash = 2; // hash of previous transaction output to spend by this input
required uint32 prev_index = 3; // index of previous output to spend
optional bytes script_sig = 4; // script signature, unset for tx to sign
optional uint32 sequence = 5 [default=4294967295]; // sequence (default=0xffffffff)
optional InputScriptType script_type = 6 [default=SPENDADDRESS]; // defines template of input script
optional MultisigRedeemScriptType multisig = 7; // Filled if input is going to spend multisig tx
optional uint64 amount = 8; // amount of previous transaction output (for segwit only)
}
/**
* Structure representing transaction output
* @used_in SimpleSignTx
* @used_in TransactionType
*/
message TxOutputType {
optional string address = 1; // target coin address in Base58 encoding
repeated uint32 address_n = 2; // BIP-32 path to derive the key from master node; has higher priority than "address"
required uint64 amount = 3; // amount to spend in satoshis
required OutputScriptType script_type = 4; // output script type
optional MultisigRedeemScriptType multisig = 5; // defines multisig address; script_type must be PAYTOMULTISIG
optional bytes op_return_data = 6; // defines op_return data; script_type must be PAYTOOPRETURN, amount must be 0
}
/**
* Structure representing compiled transaction output
* @used_in TransactionType
*/
message TxOutputBinType {
required uint64 amount = 1;
required bytes script_pubkey = 2;
}
/**
* Structure representing transaction
* @used_in SimpleSignTx
*/
message TransactionType {
optional uint32 version = 1;
repeated TxInputType inputs = 2;
repeated TxOutputBinType bin_outputs = 3;
repeated TxOutputType outputs = 5;
optional uint32 lock_time = 4;
optional uint32 inputs_cnt = 6;
optional uint32 outputs_cnt = 7;
optional bytes extra_data = 8;
optional uint32 extra_data_len = 9;
}
/**
* Structure representing request details
* @used_in TxRequest
*/
message TxRequestDetailsType {
optional uint32 request_index = 1; // device expects TxAck message from the computer
optional bytes tx_hash = 2; // tx_hash of requested transaction
optional uint32 extra_data_len = 3; // length of requested extra data
optional uint32 extra_data_offset = 4; // offset of requested extra data
}
/**
* Structure representing serialized data
* @used_in TxRequest
*/
message TxRequestSerializedType {
optional uint32 signature_index = 1; // 'signature' field contains signed input of this index
optional bytes signature = 2; // signature of the signature_index input
optional bytes serialized_tx = 3; // part of serialized and signed transaction
}
/**
* Structure representing identity data
* @used_in IdentityType
*/
message IdentityType {
optional string proto = 1; // proto part of URI
optional string user = 2; // user part of URI
optional string host = 3; // host part of URI
optional string port = 4; // port part of URI
optional string path = 5; // path part of URI
optional uint32 index = 6 [default=0]; // identity index
}

View File

@@ -0,0 +1,464 @@
// Copyright 2017 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/>.
// This file contains the implementation for interacting with the Ledger hardware
// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo:
// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc
package usbwallet
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"io"
"math/big"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// ledgerOpcode is an enumeration encoding the supported Ledger opcodes.
type ledgerOpcode byte
// ledgerParam1 is an enumeration encoding the supported Ledger parameters for
// specific opcodes. The same parameter values may be reused between opcodes.
type ledgerParam1 byte
// ledgerParam2 is an enumeration encoding the supported Ledger parameters for
// specific opcodes. The same parameter values may be reused between opcodes.
type ledgerParam2 byte
const (
ledgerOpRetrieveAddress ledgerOpcode = 0x02 // Returns the public key and Ethereum address for a given BIP 32 path
ledgerOpSignTransaction ledgerOpcode = 0x04 // Signs an Ethereum transaction after having the user validate the parameters
ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration
ledgerP1DirectlyFetchAddress ledgerParam1 = 0x00 // Return address directly from the wallet
ledgerP1ConfirmFetchAddress ledgerParam1 = 0x01 // Require a user confirmation before returning the address
ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing
ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing
ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address
ledgerP2ReturnAddressChainCode ledgerParam2 = 0x01 // Require a user confirmation before returning the address
)
// errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange
// if the device replies with a mismatching header. This usually means the device
// is in browser mode.
var errLedgerReplyInvalidHeader = errors.New("ledger: invalid reply header")
// errLedgerInvalidVersionReply is the error message returned by a Ledger version retrieval
// when a response does arrive, but it does not contain the expected data.
var errLedgerInvalidVersionReply = errors.New("ledger: invalid version reply")
// ledgerDriver implements the communication with a Ledger hardware wallet.
type ledgerDriver struct {
device io.ReadWriter // USB device connection to communicate through
version [3]byte // Current version of the Ledger firmware (zero if app is offline)
browser bool // Flag whether the Ledger is in browser mode (reply channel mismatch)
failure error // Any failure that would make the device unusable
log log.Logger // Contextual logger to tag the ledger with its id
}
// newLedgerDriver creates a new instance of a Ledger USB protocol driver.
func newLedgerDriver(logger log.Logger) driver {
return &ledgerDriver{
log: logger,
}
}
// Status implements usbwallet.driver, returning various states the Ledger can
// currently be in.
func (w *ledgerDriver) Status() (string, error) {
if w.failure != nil {
return fmt.Sprintf("Failed: %v", w.failure), w.failure
}
if w.browser {
return "Ethereum app in browser mode", w.failure
}
if w.offline() {
return "Ethereum app offline", w.failure
}
return fmt.Sprintf("Ethereum app v%d.%d.%d online", w.version[0], w.version[1], w.version[2]), w.failure
}
// offline returns whether the wallet and the Ethereum app is offline or not.
//
// The method assumes that the state lock is held!
func (w *ledgerDriver) offline() bool {
return w.version == [3]byte{0, 0, 0}
}
// Open implements usbwallet.driver, attempting to initialize the connection to the
// Ledger hardware wallet. The Ledger does not require a user passphrase, so that
// parameter is silently discarded.
func (w *ledgerDriver) Open(device io.ReadWriter, passphrase string) error {
w.device, w.failure = device, nil
_, err := w.ledgerDerive(accounts.DefaultBaseDerivationPath)
if err != nil {
// Ethereum app is not running or in browser mode, nothing more to do, return
if err == errLedgerReplyInvalidHeader {
w.browser = true
}
return nil
}
// Try to resolve the Ethereum app's version, will fail prior to v1.0.2
if w.version, err = w.ledgerVersion(); err != nil {
w.version = [3]byte{1, 0, 0} // Assume worst case, can't verify if v1.0.0 or v1.0.1
}
return nil
}
// Close implements usbwallet.driver, cleaning up and metadata maintained within
// the Ledger driver.
func (w *ledgerDriver) Close() error {
w.browser, w.version = false, [3]byte{}
return nil
}
// Heartbeat implements usbwallet.driver, performing a sanity check against the
// Ledger to see if it's still online.
func (w *ledgerDriver) Heartbeat() error {
if _, err := w.ledgerVersion(); err != nil && err != errLedgerInvalidVersionReply {
w.failure = err
return err
}
return nil
}
// Derive implements usbwallet.driver, sending a derivation request to the Ledger
// and returning the Ethereum address located on that derivation path.
func (w *ledgerDriver) Derive(path accounts.DerivationPath) (common.Address, error) {
return w.ledgerDerive(path)
}
// SignTx implements usbwallet.driver, sending the transaction to the Ledger and
// waiting for the user to confirm or deny the transaction.
//
// Note, if the version of the Ethereum application running on the Ledger wallet is
// too old to sign EIP-155 transactions, but such is requested nonetheless, an error
// will be returned opposed to silently signing in Homestead mode.
func (w *ledgerDriver) SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
// If the Ethereum app doesn't run, abort
if w.offline() {
return common.Address{}, nil, accounts.ErrWalletClosed
}
// Ensure the wallet is capable of signing the given transaction
if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 {
return common.Address{}, nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2])
}
// All infos gathered and metadata checks out, request signing
return w.ledgerSign(path, tx, chainID)
}
// ledgerVersion retrieves the current version of the Ethereum wallet app running
// on the Ledger wallet.
//
// The version retrieval protocol is defined as follows:
//
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+----+---
// E0 | 06 | 00 | 00 | 00 | 04
//
// With no input data, and the output data being:
//
// Description | Length
// ---------------------------------------------------+--------
// Flags 01: arbitrary data signature enabled by user | 1 byte
// Application major version | 1 byte
// Application minor version | 1 byte
// Application patch version | 1 byte
func (w *ledgerDriver) ledgerVersion() ([3]byte, error) {
// Send the request and wait for the response
reply, err := w.ledgerExchange(ledgerOpGetConfiguration, 0, 0, nil)
if err != nil {
return [3]byte{}, err
}
if len(reply) != 4 {
return [3]byte{}, errLedgerInvalidVersionReply
}
// Cache the version for future reference
var version [3]byte
copy(version[:], reply[1:])
return version, nil
}
// ledgerDerive retrieves the currently active Ethereum address from a Ledger
// wallet at the specified derivation path.
//
// The address derivation protocol is defined as follows:
//
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+-----+---
// E0 | 02 | 00 return address
// 01 display address and confirm before returning
// | 00: do not return the chain code
// | 01: return the chain code
// | var | 00
//
// Where the input data is:
//
// Description | Length
// -------------------------------------------------+--------
// Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes
// ... | 4 bytes
// Last derivation index (big endian) | 4 bytes
//
// And the output data is:
//
// Description | Length
// ------------------------+-------------------
// Public Key length | 1 byte
// Uncompressed Public Key | arbitrary
// Ethereum address length | 1 byte
// Ethereum address | 40 bytes hex ascii
// Chain code if requested | 32 bytes
func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, error) {
// Flatten the derivation path into the Ledger request
path := make([]byte, 1+4*len(derivationPath))
path[0] = byte(len(derivationPath))
for i, component := range derivationPath {
binary.BigEndian.PutUint32(path[1+4*i:], component)
}
// Send the request and wait for the response
reply, err := w.ledgerExchange(ledgerOpRetrieveAddress, ledgerP1DirectlyFetchAddress, ledgerP2DiscardAddressChainCode, path)
if err != nil {
return common.Address{}, err
}
// Discard the public key, we don't need that for now
if len(reply) < 1 || len(reply) < 1+int(reply[0]) {
return common.Address{}, errors.New("reply lacks public key entry")
}
reply = reply[1+int(reply[0]):]
// Extract the Ethereum hex address string
if len(reply) < 1 || len(reply) < 1+int(reply[0]) {
return common.Address{}, errors.New("reply lacks address entry")
}
hexstr := reply[1 : 1+int(reply[0])]
// Decode the hex sting into an Ethereum address and return
var address common.Address
hex.Decode(address[:], hexstr)
return address, nil
}
// ledgerSign sends the transaction to the Ledger wallet, and waits for the user
// to confirm or deny the transaction.
//
// The transaction signing protocol is defined as follows:
//
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+-----+---
// E0 | 04 | 00: first transaction data block
// 80: subsequent transaction data block
// | 00 | variable | variable
//
// Where the input for the first transaction block (first 255 bytes) is:
//
// Description | Length
// -------------------------------------------------+----------
// Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes
// ... | 4 bytes
// Last derivation index (big endian) | 4 bytes
// RLP transaction chunk | arbitrary
//
// And the input for subsequent transaction blocks (first 255 bytes) are:
//
// Description | Length
// ----------------------+----------
// RLP transaction chunk | arbitrary
//
// And the output data is:
//
// Description | Length
// ------------+---------
// signature V | 1 byte
// signature R | 32 bytes
// signature S | 32 bytes
func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
// Flatten the derivation path into the Ledger request
path := make([]byte, 1+4*len(derivationPath))
path[0] = byte(len(derivationPath))
for i, component := range derivationPath {
binary.BigEndian.PutUint32(path[1+4*i:], component)
}
// Create the transaction RLP based on whether legacy or EIP155 signing was requeste
var (
txrlp []byte
err error
)
if chainID == nil {
if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data()}); err != nil {
return common.Address{}, nil, err
}
} else {
if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), chainID, big.NewInt(0), big.NewInt(0)}); err != nil {
return common.Address{}, nil, err
}
}
payload := append(path, txrlp...)
// Send the request and wait for the response
var (
op = ledgerP1InitTransactionData
reply []byte
)
for len(payload) > 0 {
// Calculate the size of the next data chunk
chunk := 255
if chunk > len(payload) {
chunk = len(payload)
}
// Send the chunk over, ensuring it's processed correctly
reply, err = w.ledgerExchange(ledgerOpSignTransaction, op, 0, payload[:chunk])
if err != nil {
return common.Address{}, nil, err
}
// Shift the payload and ensure subsequent chunks are marked as such
payload = payload[chunk:]
op = ledgerP1ContTransactionData
}
// Extract the Ethereum signature and do a sanity validation
if len(reply) != 65 {
return common.Address{}, nil, errors.New("reply lacks signature")
}
signature := append(reply[1:], reply[0])
// Create the correct signer and signature transform based on the chain ID
var signer types.Signer
if chainID == nil {
signer = new(types.HomesteadSigner)
} else {
signer = types.NewEIP155Signer(chainID)
signature[64] = signature[64] - byte(chainID.Uint64()*2+35)
}
signed, err := tx.WithSignature(signer, signature)
if err != nil {
return common.Address{}, nil, err
}
sender, err := types.Sender(signer, signed)
if err != nil {
return common.Address{}, nil, err
}
return sender, signed, nil
}
// ledgerExchange performs a data exchange with the Ledger wallet, sending it a
// message and retrieving the response.
//
// The common transport header is defined as follows:
//
// Description | Length
// --------------------------------------+----------
// Communication channel ID (big endian) | 2 bytes
// Command tag | 1 byte
// Packet sequence index (big endian) | 2 bytes
// Payload | arbitrary
//
// The Communication channel ID allows commands multiplexing over the same
// physical link. It is not used for the time being, and should be set to 0101
// to avoid compatibility issues with implementations ignoring a leading 00 byte.
//
// The Command tag describes the message content. Use TAG_APDU (0x05) for standard
// APDU payloads, or TAG_PING (0x02) for a simple link test.
//
// The Packet sequence index describes the current sequence for fragmented payloads.
// The first fragment index is 0x00.
//
// APDU Command payloads are encoded as follows:
//
// Description | Length
// -----------------------------------
// APDU length (big endian) | 2 bytes
// APDU CLA | 1 byte
// APDU INS | 1 byte
// APDU P1 | 1 byte
// APDU P2 | 1 byte
// APDU length | 1 byte
// Optional APDU data | arbitrary
func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) {
// Construct the message payload, possibly split into multiple chunks
apdu := make([]byte, 2, 7+len(data))
binary.BigEndian.PutUint16(apdu, uint16(5+len(data)))
apdu = append(apdu, []byte{0xe0, byte(opcode), byte(p1), byte(p2), byte(len(data))}...)
apdu = append(apdu, data...)
// Stream all the chunks to the device
header := []byte{0x01, 0x01, 0x05, 0x00, 0x00} // Channel ID and command tag appended
chunk := make([]byte, 64)
space := len(chunk) - len(header)
for i := 0; len(apdu) > 0; i++ {
// Construct the new message to stream
chunk = append(chunk[:0], header...)
binary.BigEndian.PutUint16(chunk[3:], uint16(i))
if len(apdu) > space {
chunk = append(chunk, apdu[:space]...)
apdu = apdu[space:]
} else {
chunk = append(chunk, apdu...)
apdu = nil
}
// Send over to the device
w.log.Trace("Data chunk sent to the Ledger", "chunk", hexutil.Bytes(chunk))
if _, err := w.device.Write(chunk); err != nil {
return nil, err
}
}
// Stream the reply back from the wallet in 64 byte chunks
var reply []byte
chunk = chunk[:64] // Yeah, we surely have enough space
for {
// Read the next chunk from the Ledger wallet
if _, err := io.ReadFull(w.device, chunk); err != nil {
return nil, err
}
w.log.Trace("Data chunk received from the Ledger", "chunk", hexutil.Bytes(chunk))
// Make sure the transport header matches
if chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != 0x05 {
return nil, errLedgerReplyInvalidHeader
}
// If it's the first chunk, retrieve the total message length
var payload []byte
if chunk[3] == 0x00 && chunk[4] == 0x00 {
reply = make([]byte, 0, int(binary.BigEndian.Uint16(chunk[5:7])))
payload = chunk[7:]
} else {
payload = chunk[5:]
}
// Append to the reply and stop when filled up
if left := cap(reply) - len(reply); left > len(payload) {
reply = append(reply, payload...)
} else {
reply = append(reply, payload[:left]...)
break
}
}
return reply[:len(reply)-2], nil
}

View File

@@ -0,0 +1,330 @@
// Copyright 2017 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/>.
// This file contains the implementation for interacting with the Trezor hardware
// wallets. The wire protocol spec can be found on the SatoshiLabs website:
// https://doc.satoshilabs.com/trezor-tech/api-protobuf.html
package usbwallet
import (
"encoding/binary"
"errors"
"fmt"
"io"
"math/big"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/golang/protobuf/proto"
)
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
// this case, the calling application should display a pinpad and send back the
// encoded passphrase.
var ErrTrezorPINNeeded = errors.New("trezor: pin needed")
// errTrezorReplyInvalidHeader is the error message returned by a Trezor data exchange
// if the device replies with a mismatching header. This usually means the device
// is in browser mode.
var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header")
// trezorDriver implements the communication with a Trezor hardware wallet.
type trezorDriver struct {
device io.ReadWriter // USB device connection to communicate through
version [3]uint32 // Current version of the Trezor firmware
label string // Current textual label of the Trezor device
pinwait bool // Flags whether the device is waiting for PIN entry
failure error // Any failure that would make the device unusable
log log.Logger // Contextual logger to tag the trezor with its id
}
// newTrezorDriver creates a new instance of a Trezor USB protocol driver.
func newTrezorDriver(logger log.Logger) driver {
return &trezorDriver{
log: logger,
}
}
// Status implements accounts.Wallet, always whether the Trezor is opened, closed
// or whether the Ethereum app was not started on it.
func (w *trezorDriver) Status() (string, error) {
if w.failure != nil {
return fmt.Sprintf("Failed: %v", w.failure), w.failure
}
if w.device == nil {
return "Closed", w.failure
}
if w.pinwait {
return fmt.Sprintf("Trezor v%d.%d.%d '%s' waiting for PIN", w.version[0], w.version[1], w.version[2], w.label), w.failure
}
return fmt.Sprintf("Trezor v%d.%d.%d '%s' online", w.version[0], w.version[1], w.version[2], w.label), w.failure
}
// Open implements usbwallet.driver, attempting to initialize the connection to
// the Trezor hardware wallet. Initializing the Trezor is a two phase operation:
// * The first phase is to initialize the connection and read the wallet's
// features. This phase is invoked is the provided passphrase is empty. The
// device will display the pinpad as a result and will return an appropriate
// error to notify the user that a second open phase is needed.
// * The second phase is to unlock access to the Trezor, which is done by the
// user actually providing a passphrase mapping a keyboard keypad to the pin
// number of the user (shuffled according to the pinpad displayed).
func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error {
w.device, w.failure = device, nil
// If phase 1 is requested, init the connection and wait for user callback
if passphrase == "" {
// If we're already waiting for a PIN entry, insta-return
if w.pinwait {
return ErrTrezorPINNeeded
}
// Initialize a connection to the device
features := new(trezor.Features)
if _, err := w.trezorExchange(&trezor.Initialize{}, features); err != nil {
return err
}
w.version = [3]uint32{features.GetMajorVersion(), features.GetMinorVersion(), features.GetPatchVersion()}
w.label = features.GetLabel()
// Do a manual ping, forcing the device to ask for its PIN
askPin := true
res, err := w.trezorExchange(&trezor.Ping{PinProtection: &askPin}, new(trezor.PinMatrixRequest), new(trezor.Success))
if err != nil {
return err
}
// Only return the PIN request if the device wasn't unlocked until now
if res == 1 {
return nil // Device responded with trezor.Success
}
w.pinwait = true
return ErrTrezorPINNeeded
}
// Phase 2 requested with actual PIN entry
w.pinwait = false
if _, err := w.trezorExchange(&trezor.PinMatrixAck{Pin: &passphrase}, new(trezor.Success)); err != nil {
w.failure = err
return err
}
return nil
}
// Close implements usbwallet.driver, cleaning up and metadata maintained within
// the Trezor driver.
func (w *trezorDriver) Close() error {
w.version, w.label, w.pinwait = [3]uint32{}, "", false
return nil
}
// Heartbeat implements usbwallet.driver, performing a sanity check against the
// Trezor to see if it's still online.
func (w *trezorDriver) Heartbeat() error {
if _, err := w.trezorExchange(&trezor.Ping{}, new(trezor.Success)); err != nil {
w.failure = err
return err
}
return nil
}
// Derive implements usbwallet.driver, sending a derivation request to the Trezor
// and returning the Ethereum address located on that derivation path.
func (w *trezorDriver) Derive(path accounts.DerivationPath) (common.Address, error) {
return w.trezorDerive(path)
}
// SignTx implements usbwallet.driver, sending the transaction to the Trezor and
// waiting for the user to confirm or deny the transaction.
func (w *trezorDriver) SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
if w.device == nil {
return common.Address{}, nil, accounts.ErrWalletClosed
}
return w.trezorSign(path, tx, chainID)
}
// trezorDerive sends a derivation request to the Trezor device and returns the
// Ethereum address located on that path.
func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, error) {
address := new(trezor.EthereumAddress)
if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil {
return common.Address{}, err
}
return common.BytesToAddress(address.GetAddress()), nil
}
// trezorSign sends the transaction to the Trezor wallet, and waits for the user
// to confirm or deny the transaction.
func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
// Create the transaction initiation message
data := tx.Data()
length := uint32(len(data))
request := &trezor.EthereumSignTx{
AddressN: derivationPath,
Nonce: new(big.Int).SetUint64(tx.Nonce()).Bytes(),
GasPrice: tx.GasPrice().Bytes(),
GasLimit: new(big.Int).SetUint64(tx.Gas()).Bytes(),
Value: tx.Value().Bytes(),
DataLength: &length,
}
if to := tx.To(); to != nil {
request.To = (*to)[:] // Non contract deploy, set recipient explicitly
}
if length > 1024 { // Send the data chunked if that was requested
request.DataInitialChunk, data = data[:1024], data[1024:]
} else {
request.DataInitialChunk, data = data, nil
}
if chainID != nil { // EIP-155 transaction, set chain ID explicitly (only 32 bit is supported!?)
id := uint32(chainID.Int64())
request.ChainId = &id
}
// Send the initiation message and stream content until a signature is returned
response := new(trezor.EthereumTxRequest)
if _, err := w.trezorExchange(request, response); err != nil {
return common.Address{}, nil, err
}
for response.DataLength != nil && int(*response.DataLength) <= len(data) {
chunk := data[:*response.DataLength]
data = data[*response.DataLength:]
if _, err := w.trezorExchange(&trezor.EthereumTxAck{DataChunk: chunk}, response); err != nil {
return common.Address{}, nil, err
}
}
// Extract the Ethereum signature and do a sanity validation
if len(response.GetSignatureR()) == 0 || len(response.GetSignatureS()) == 0 || response.GetSignatureV() == 0 {
return common.Address{}, nil, errors.New("reply lacks signature")
}
signature := append(append(response.GetSignatureR(), response.GetSignatureS()...), byte(response.GetSignatureV()))
// Create the correct signer and signature transform based on the chain ID
var signer types.Signer
if chainID == nil {
signer = new(types.HomesteadSigner)
} else {
signer = types.NewEIP155Signer(chainID)
signature[64] = signature[64] - byte(chainID.Uint64()*2+35)
}
// Inject the final signature into the transaction and sanity check the sender
signed, err := tx.WithSignature(signer, signature)
if err != nil {
return common.Address{}, nil, err
}
sender, err := types.Sender(signer, signed)
if err != nil {
return common.Address{}, nil, err
}
return sender, signed, nil
}
// trezorExchange performs a data exchange with the Trezor wallet, sending it a
// message and retrieving the response. If multiple responses are possible, the
// method will also return the index of the destination object used.
func (w *trezorDriver) trezorExchange(req proto.Message, results ...proto.Message) (int, error) {
// Construct the original message payload to chunk up
data, err := proto.Marshal(req)
if err != nil {
return 0, err
}
payload := make([]byte, 8+len(data))
copy(payload, []byte{0x23, 0x23})
binary.BigEndian.PutUint16(payload[2:], trezor.Type(req))
binary.BigEndian.PutUint32(payload[4:], uint32(len(data)))
copy(payload[8:], data)
// Stream all the chunks to the device
chunk := make([]byte, 64)
chunk[0] = 0x3f // Report ID magic number
for len(payload) > 0 {
// Construct the new message to stream, padding with zeroes if needed
if len(payload) > 63 {
copy(chunk[1:], payload[:63])
payload = payload[63:]
} else {
copy(chunk[1:], payload)
copy(chunk[1+len(payload):], make([]byte, 63-len(payload)))
payload = nil
}
// Send over to the device
w.log.Trace("Data chunk sent to the Trezor", "chunk", hexutil.Bytes(chunk))
if _, err := w.device.Write(chunk); err != nil {
return 0, err
}
}
// Stream the reply back from the wallet in 64 byte chunks
var (
kind uint16
reply []byte
)
for {
// Read the next chunk from the Trezor wallet
if _, err := io.ReadFull(w.device, chunk); err != nil {
return 0, err
}
w.log.Trace("Data chunk received from the Trezor", "chunk", hexutil.Bytes(chunk))
// Make sure the transport header matches
if chunk[0] != 0x3f || (len(reply) == 0 && (chunk[1] != 0x23 || chunk[2] != 0x23)) {
return 0, errTrezorReplyInvalidHeader
}
// If it's the first chunk, retrieve the reply message type and total message length
var payload []byte
if len(reply) == 0 {
kind = binary.BigEndian.Uint16(chunk[3:5])
reply = make([]byte, 0, int(binary.BigEndian.Uint32(chunk[5:9])))
payload = chunk[9:]
} else {
payload = chunk[1:]
}
// Append to the reply and stop when filled up
if left := cap(reply) - len(reply); left > len(payload) {
reply = append(reply, payload...)
} else {
reply = append(reply, payload[:left]...)
break
}
}
// Try to parse the reply into the requested reply message
if kind == uint16(trezor.MessageType_MessageType_Failure) {
// Trezor returned a failure, extract and return the message
failure := new(trezor.Failure)
if err := proto.Unmarshal(reply, failure); err != nil {
return 0, err
}
return 0, errors.New("trezor: " + failure.GetMessage())
}
if kind == uint16(trezor.MessageType_MessageType_ButtonRequest) {
// Trezor is waiting for user confirmation, ack and wait for the next message
return w.trezorExchange(&trezor.ButtonAck{}, results...)
}
for i, res := range results {
if trezor.Type(res) == kind {
return i, proto.Unmarshal(reply, res)
}
}
expected := make([]string, len(results))
for i, res := range results {
expected[i] = trezor.Name(trezor.Type(res))
}
return 0, fmt.Errorf("trezor: expected reply types %s, got %s", expected, trezor.Name(kind))
}

View File

@@ -0,0 +1,562 @@
// Copyright 2017 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 usbwallet implements support for USB hardware wallets.
package usbwallet
import (
"context"
"fmt"
"io"
"math/big"
"sync"
"time"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/karalabe/hid"
)
// Maximum time between wallet health checks to detect USB unplugs.
const heartbeatCycle = time.Second
// Minimum time to wait between self derivation attempts, even it the user is
// requesting accounts like crazy.
const selfDeriveThrottling = time.Second
// driver defines the vendor specific functionality hardware wallets instances
// must implement to allow using them with the wallet lifecycle management.
type driver interface {
// Status returns a textual status to aid the user in the current state of the
// wallet. It also returns an error indicating any failure the wallet might have
// encountered.
Status() (string, error)
// Open initializes access to a wallet instance. The passphrase parameter may
// or may not be used by the implementation of a particular wallet instance.
Open(device io.ReadWriter, passphrase string) error
// Close releases any resources held by an open wallet instance.
Close() error
// Heartbeat performs a sanity check against the hardware wallet to see if it
// is still online and healthy.
Heartbeat() error
// Derive sends a derivation request to the USB device and returns the Ethereum
// address located on that path.
Derive(path accounts.DerivationPath) (common.Address, error)
// SignTx sends the transaction to the USB device and waits for the user to confirm
// or deny the transaction.
SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error)
}
// wallet represents the common functionality shared by all USB hardware
// wallets to prevent reimplementing the same complex maintenance mechanisms
// for different vendors.
type wallet struct {
hub *Hub // USB hub scanning
driver driver // Hardware implementation of the low level device operations
url *accounts.URL // Textual URL uniquely identifying this wallet
info hid.DeviceInfo // Known USB device infos about the wallet
device *hid.Device // USB device advertising itself as a hardware wallet
accounts []accounts.Account // List of derive accounts pinned on the hardware wallet
paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
deriveNextPath accounts.DerivationPath // Next derivation path for account auto-discovery
deriveNextAddr common.Address // Next derived account address for auto-discovery
deriveChain ethereum.ChainStateReader // Blockchain state reader to discover used account with
deriveReq chan chan struct{} // Channel to request a self-derivation on
deriveQuit chan chan error // Channel to terminate the self-deriver with
healthQuit chan chan error
// Locking a hardware wallet is a bit special. Since hardware devices are lower
// performing, any communication with them might take a non negligible amount of
// time. Worse still, waiting for user confirmation can take arbitrarily long,
// but exclusive communication must be upheld during. Locking the entire wallet
// in the mean time however would stall any parts of the system that don't want
// to communicate, just read some state (e.g. list the accounts).
//
// As such, a hardware wallet needs two locks to function correctly. A state
// lock can be used to protect the wallet's software-side internal state, which
// must not be held exlusively during hardware communication. A communication
// lock can be used to achieve exclusive access to the device itself, this one
// however should allow "skipping" waiting for operations that might want to
// use the device, but can live without too (e.g. account self-derivation).
//
// Since we have two locks, it's important to know how to properly use them:
// - Communication requires the `device` to not change, so obtaining the
// commsLock should be done after having a stateLock.
// - Communication must not disable read access to the wallet state, so it
// must only ever hold a *read* lock to stateLock.
commsLock chan struct{} // Mutex (buf=1) for the USB comms without keeping the state locked
stateLock sync.RWMutex // Protects read and write access to the wallet struct fields
log log.Logger // Contextual logger to tag the base with its id
}
// URL implements accounts.Wallet, returning the URL of the USB hardware device.
func (w *wallet) URL() accounts.URL {
return *w.url // Immutable, no need for a lock
}
// Status implements accounts.Wallet, returning a custom status message from the
// underlying vendor-specific hardware wallet implementation.
func (w *wallet) Status() (string, error) {
w.stateLock.RLock() // No device communication, state lock is enough
defer w.stateLock.RUnlock()
status, failure := w.driver.Status()
if w.device == nil {
return "Closed", failure
}
return status, failure
}
// Open implements accounts.Wallet, attempting to open a USB connection to the
// hardware wallet.
func (w *wallet) Open(passphrase string) error {
w.stateLock.Lock() // State lock is enough since there's no connection yet at this point
defer w.stateLock.Unlock()
// If the device was already opened once, refuse to try again
if w.paths != nil {
return accounts.ErrWalletAlreadyOpen
}
// Make sure the actual device connection is done only once
if w.device == nil {
device, err := w.info.Open()
if err != nil {
return err
}
w.device = device
w.commsLock = make(chan struct{}, 1)
w.commsLock <- struct{}{} // Enable lock
}
// Delegate device initialization to the underlying driver
if err := w.driver.Open(w.device, passphrase); err != nil {
return err
}
// Connection successful, start life-cycle management
w.paths = make(map[common.Address]accounts.DerivationPath)
w.deriveReq = make(chan chan struct{})
w.deriveQuit = make(chan chan error)
w.healthQuit = make(chan chan error)
go w.heartbeat()
go w.selfDerive()
// Notify anyone listening for wallet events that a new device is accessible
go w.hub.updateFeed.Send(accounts.WalletEvent{Wallet: w, Kind: accounts.WalletOpened})
return nil
}
// heartbeat is a health check loop for the USB wallets to periodically verify
// whether they are still present or if they malfunctioned.
func (w *wallet) heartbeat() {
w.log.Debug("USB wallet health-check started")
defer w.log.Debug("USB wallet health-check stopped")
// Execute heartbeat checks until termination or error
var (
errc chan error
err error
)
for errc == nil && err == nil {
// Wait until termination is requested or the heartbeat cycle arrives
select {
case errc = <-w.healthQuit:
// Termination requested
continue
case <-time.After(heartbeatCycle):
// Heartbeat time
}
// Execute a tiny data exchange to see responsiveness
w.stateLock.RLock()
if w.device == nil {
// Terminated while waiting for the lock
w.stateLock.RUnlock()
continue
}
<-w.commsLock // Don't lock state while resolving version
err = w.driver.Heartbeat()
w.commsLock <- struct{}{}
w.stateLock.RUnlock()
if err != nil {
w.stateLock.Lock() // Lock state to tear the wallet down
w.close()
w.stateLock.Unlock()
}
// Ignore non hardware related errors
err = nil
}
// In case of error, wait for termination
if err != nil {
w.log.Debug("USB wallet health-check failed", "err", err)
errc = <-w.healthQuit
}
errc <- err
}
// Close implements accounts.Wallet, closing the USB connection to the device.
func (w *wallet) Close() error {
// Ensure the wallet was opened
w.stateLock.RLock()
hQuit, dQuit := w.healthQuit, w.deriveQuit
w.stateLock.RUnlock()
// Terminate the health checks
var herr error
if hQuit != nil {
errc := make(chan error)
hQuit <- errc
herr = <-errc // Save for later, we *must* close the USB
}
// Terminate the self-derivations
var derr error
if dQuit != nil {
errc := make(chan error)
dQuit <- errc
derr = <-errc // Save for later, we *must* close the USB
}
// Terminate the device connection
w.stateLock.Lock()
defer w.stateLock.Unlock()
w.healthQuit = nil
w.deriveQuit = nil
w.deriveReq = nil
if err := w.close(); err != nil {
return err
}
if herr != nil {
return herr
}
return derr
}
// close is the internal wallet closer that terminates the USB connection and
// resets all the fields to their defaults.
//
// Note, close assumes the state lock is held!
func (w *wallet) close() error {
// Allow duplicate closes, especially for health-check failures
if w.device == nil {
return nil
}
// Close the device, clear everything, then return
w.device.Close()
w.device = nil
w.accounts, w.paths = nil, nil
w.driver.Close()
return nil
}
// Accounts implements accounts.Wallet, returning the list of accounts pinned to
// the USB hardware wallet. If self-derivation was enabled, the account list is
// periodically expanded based on current chain state.
func (w *wallet) Accounts() []accounts.Account {
// Attempt self-derivation if it's running
reqc := make(chan struct{}, 1)
select {
case w.deriveReq <- reqc:
// Self-derivation request accepted, wait for it
<-reqc
default:
// Self-derivation offline, throttled or busy, skip
}
// Return whatever account list we ended up with
w.stateLock.RLock()
defer w.stateLock.RUnlock()
cpy := make([]accounts.Account, len(w.accounts))
copy(cpy, w.accounts)
return cpy
}
// selfDerive is an account derivation loop that upon request attempts to find
// new non-zero accounts.
func (w *wallet) selfDerive() {
w.log.Debug("USB wallet self-derivation started")
defer w.log.Debug("USB wallet self-derivation stopped")
// Execute self-derivations until termination or error
var (
reqc chan struct{}
errc chan error
err error
)
for errc == nil && err == nil {
// Wait until either derivation or termination is requested
select {
case errc = <-w.deriveQuit:
// Termination requested
continue
case reqc = <-w.deriveReq:
// Account discovery requested
}
// Derivation needs a chain and device access, skip if either unavailable
w.stateLock.RLock()
if w.device == nil || w.deriveChain == nil {
w.stateLock.RUnlock()
reqc <- struct{}{}
continue
}
select {
case <-w.commsLock:
default:
w.stateLock.RUnlock()
reqc <- struct{}{}
continue
}
// Device lock obtained, derive the next batch of accounts
var (
accs []accounts.Account
paths []accounts.DerivationPath
nextAddr = w.deriveNextAddr
nextPath = w.deriveNextPath
context = context.Background()
)
for empty := false; !empty; {
// Retrieve the next derived Ethereum account
if nextAddr == (common.Address{}) {
if nextAddr, err = w.driver.Derive(nextPath); err != nil {
w.log.Warn("USB wallet account derivation failed", "err", err)
break
}
}
// Check the account's status against the current chain state
var (
balance *big.Int
nonce uint64
)
balance, err = w.deriveChain.BalanceAt(context, nextAddr, nil)
if err != nil {
w.log.Warn("USB wallet balance retrieval failed", "err", err)
break
}
nonce, err = w.deriveChain.NonceAt(context, nextAddr, nil)
if err != nil {
w.log.Warn("USB wallet nonce retrieval failed", "err", err)
break
}
// If the next account is empty, stop self-derivation, but add it nonetheless
if balance.Sign() == 0 && nonce == 0 {
empty = true
}
// We've just self-derived a new account, start tracking it locally
path := make(accounts.DerivationPath, len(nextPath))
copy(path[:], nextPath[:])
paths = append(paths, path)
account := accounts.Account{
Address: nextAddr,
URL: accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
}
accs = append(accs, account)
// Display a log message to the user for new (or previously empty accounts)
if _, known := w.paths[nextAddr]; !known || (!empty && nextAddr == w.deriveNextAddr) {
w.log.Info("USB wallet discovered new account", "address", nextAddr, "path", path, "balance", balance, "nonce", nonce)
}
// Fetch the next potential account
if !empty {
nextAddr = common.Address{}
nextPath[len(nextPath)-1]++
}
}
// Self derivation complete, release device lock
w.commsLock <- struct{}{}
w.stateLock.RUnlock()
// Insert any accounts successfully derived
w.stateLock.Lock()
for i := 0; i < len(accs); i++ {
if _, ok := w.paths[accs[i].Address]; !ok {
w.accounts = append(w.accounts, accs[i])
w.paths[accs[i].Address] = paths[i]
}
}
// Shift the self-derivation forward
// TODO(karalabe): don't overwrite changes from wallet.SelfDerive
w.deriveNextAddr = nextAddr
w.deriveNextPath = nextPath
w.stateLock.Unlock()
// Notify the user of termination and loop after a bit of time (to avoid trashing)
reqc <- struct{}{}
if err == nil {
select {
case errc = <-w.deriveQuit:
// Termination requested, abort
case <-time.After(selfDeriveThrottling):
// Waited enough, willing to self-derive again
}
}
}
// In case of error, wait for termination
if err != nil {
w.log.Debug("USB wallet self-derivation failed", "err", err)
errc = <-w.deriveQuit
}
errc <- err
}
// Contains implements accounts.Wallet, returning whether a particular account is
// or is not pinned into this wallet instance. Although we could attempt to resolve
// unpinned accounts, that would be an non-negligible hardware operation.
func (w *wallet) Contains(account accounts.Account) bool {
w.stateLock.RLock()
defer w.stateLock.RUnlock()
_, exists := w.paths[account.Address]
return exists
}
// Derive implements accounts.Wallet, deriving a new account at the specific
// derivation path. If pin is set to true, the account will be added to the list
// of tracked accounts.
func (w *wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
// Try to derive the actual account and update its URL if successful
w.stateLock.RLock() // Avoid device disappearing during derivation
if w.device == nil {
w.stateLock.RUnlock()
return accounts.Account{}, accounts.ErrWalletClosed
}
<-w.commsLock // Avoid concurrent hardware access
address, err := w.driver.Derive(path)
w.commsLock <- struct{}{}
w.stateLock.RUnlock()
// If an error occurred or no pinning was requested, return
if err != nil {
return accounts.Account{}, err
}
account := accounts.Account{
Address: address,
URL: accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
}
if !pin {
return account, nil
}
// Pinning needs to modify the state
w.stateLock.Lock()
defer w.stateLock.Unlock()
if _, ok := w.paths[address]; !ok {
w.accounts = append(w.accounts, account)
w.paths[address] = path
}
return account, nil
}
// SelfDerive implements accounts.Wallet, trying to discover accounts that the
// user used previously (based on the chain state), but ones that he/she did not
// explicitly pin to the wallet manually. To avoid chain head monitoring, self
// derivation only runs during account listing (and even then throttled).
func (w *wallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) {
w.stateLock.Lock()
defer w.stateLock.Unlock()
w.deriveNextPath = make(accounts.DerivationPath, len(base))
copy(w.deriveNextPath[:], base[:])
w.deriveNextAddr = common.Address{}
w.deriveChain = chain
}
// SignHash implements accounts.Wallet, however signing arbitrary data is not
// supported for hardware wallets, so this method will always return an error.
func (w *wallet) SignHash(account accounts.Account, hash []byte) ([]byte, error) {
return nil, accounts.ErrNotSupported
}
// SignTx implements accounts.Wallet. It sends the transaction over to the Ledger
// wallet to request a confirmation from the user. It returns either the signed
// transaction or a failure if the user denied the transaction.
//
// Note, if the version of the Ethereum application running on the Ledger wallet is
// too old to sign EIP-155 transactions, but such is requested nonetheless, an error
// will be returned opposed to silently signing in Homestead mode.
func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
w.stateLock.RLock() // Comms have own mutex, this is for the state fields
defer w.stateLock.RUnlock()
// If the wallet is closed, abort
if w.device == nil {
return nil, accounts.ErrWalletClosed
}
// Make sure the requested account is contained within
path, ok := w.paths[account.Address]
if !ok {
return nil, accounts.ErrUnknownAccount
}
// All infos gathered and metadata checks out, request signing
<-w.commsLock
defer func() { w.commsLock <- struct{}{} }()
// Ensure the device isn't screwed with while user confirmation is pending
// TODO(karalabe): remove if hotplug lands on Windows
w.hub.commsLock.Lock()
w.hub.commsPend++
w.hub.commsLock.Unlock()
defer func() {
w.hub.commsLock.Lock()
w.hub.commsPend--
w.hub.commsLock.Unlock()
}()
// Sign the transaction and verify the sender to avoid hardware fault surprises
sender, signed, err := w.driver.SignTx(path, tx, chainID)
if err != nil {
return nil, err
}
if sender != account.Address {
return nil, fmt.Errorf("signer mismatch: expected %s, got %s", account.Address.Hex(), sender.Hex())
}
return signed, nil
}
// SignHashWithPassphrase implements accounts.Wallet, however signing arbitrary
// data is not supported for Ledger wallets, so this method will always return
// an error.
func (w *wallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) {
return w.SignHash(account, hash)
}
// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
// transaction with the given account using passphrase as extra authentication.
// Since USB wallets don't rely on passphrases, these are silently ignored.
func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
return w.SignTx(account, tx, chainID)
}

View File

@@ -1,113 +0,0 @@
// Copyright 2016 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 darwin,!ios freebsd linux,!arm64 netbsd solaris windows
package accounts
import (
"time"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/rjeczalik/notify"
)
type watcher struct {
ac *addrCache
starting bool
running bool
ev chan notify.EventInfo
quit chan struct{}
}
func newWatcher(ac *addrCache) *watcher {
return &watcher{
ac: ac,
ev: make(chan notify.EventInfo, 10),
quit: make(chan struct{}),
}
}
// starts the watcher loop in the background.
// Start a watcher in the background if that's not already in progress.
// The caller must hold w.ac.mu.
func (w *watcher) start() {
if w.starting || w.running {
return
}
w.starting = true
go w.loop()
}
func (w *watcher) close() {
close(w.quit)
}
func (w *watcher) loop() {
defer func() {
w.ac.mu.Lock()
w.running = false
w.starting = false
w.ac.mu.Unlock()
}()
err := notify.Watch(w.ac.keydir, w.ev, notify.All)
if err != nil {
glog.V(logger.Detail).Infof("can't watch %s: %v", w.ac.keydir, err)
return
}
defer notify.Stop(w.ev)
glog.V(logger.Detail).Infof("now watching %s", w.ac.keydir)
defer glog.V(logger.Detail).Infof("no longer watching %s", w.ac.keydir)
w.ac.mu.Lock()
w.running = true
w.ac.mu.Unlock()
// Wait for file system events and reload.
// When an event occurs, the reload call is delayed a bit so that
// multiple events arriving quickly only cause a single reload.
var (
debounce = time.NewTimer(0)
debounceDuration = 500 * time.Millisecond
inCycle, hadEvent bool
)
defer debounce.Stop()
for {
select {
case <-w.quit:
return
case <-w.ev:
if !inCycle {
debounce.Reset(debounceDuration)
inCycle = true
} else {
hadEvent = true
}
case <-debounce.C:
w.ac.mu.Lock()
w.ac.reload()
w.ac.mu.Unlock()
if hadEvent {
debounce.Reset(debounceDuration)
inCycle, hadEvent = true, false
} else {
inCycle, hadEvent = false, false
}
}
}
}

View File

@@ -21,20 +21,20 @@ environment:
PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH%
install:
- git submodule update --init
- rmdir C:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.3.windows-amd64.zip
- 7z x go1.7.3.windows-amd64.zip -y -oC:\ > NUL
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.9.2.windows-%GETH_ARCH%.zip
- 7z x go1.9.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
- go version
- gcc --version
build_script:
- go run build\ci.go install -arch %GETH_ARCH%
- go run build\ci.go install
after_build:
- go run build\ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
- go run build\ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
- go run build\ci.go archive -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
- go run build\ci.go nsis -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
test_script:
- set GOARCH=%GETH_ARCH%
- set CGO_ENABLED=1
- go run build\ci.go test -vet -coverage
- go run build\ci.go test -coverage

561
bmt/bmt.go Normal file
View File

@@ -0,0 +1,561 @@
// Copyright 2017 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 bmt provides a binary merkle tree implementation
package bmt
import (
"fmt"
"hash"
"io"
"strings"
"sync"
"sync/atomic"
)
/*
Binary Merkle Tree Hash is a hash function over arbitrary datachunks of limited size
It is defined as the root hash of the binary merkle tree built over fixed size segments
of the underlying chunk using any base hash function (e.g keccak 256 SHA3)
It is used as the chunk hash function in swarm which in turn is the basis for the
128 branching swarm hash http://swarm-guide.readthedocs.io/en/latest/architecture.html#swarm-hash
The BMT is optimal for providing compact inclusion proofs, i.e. prove that a
segment is a substring of a chunk starting at a particular offset
The size of the underlying segments is fixed at 32 bytes (called the resolution
of the BMT hash), the EVM word size to optimize for on-chain BMT verification
as well as the hash size optimal for inclusion proofs in the merkle tree of the swarm hash.
Two implementations are provided:
* RefHasher is optimized for code simplicity and meant as a reference implementation
* Hasher is optimized for speed taking advantage of concurrency with minimalistic
control structure to coordinate the concurrent routines
It implements the ChunkHash interface as well as the go standard hash.Hash interface
*/
const (
// DefaultSegmentCount is the maximum number of segments of the underlying chunk
DefaultSegmentCount = 128 // Should be equal to storage.DefaultBranches
// DefaultPoolSize is the maximum number of bmt trees used by the hashers, i.e,
// the maximum number of concurrent BMT hashing operations performed by the same hasher
DefaultPoolSize = 8
)
// BaseHasher is a hash.Hash constructor function used for the base hash of the BMT.
type BaseHasher func() hash.Hash
// Hasher a reusable hasher for fixed maximum size chunks representing a BMT
// implements the hash.Hash interface
// reuse pool of Tree-s for amortised memory allocation and resource control
// supports order-agnostic concurrent segment writes
// as well as sequential read and write
// can not be called concurrently on more than one chunk
// can be further appended after Sum
// Reset gives back the Tree to the pool and guaranteed to leave
// the tree and itself in a state reusable for hashing a new chunk
type Hasher struct {
pool *TreePool // BMT resource pool
bmt *Tree // prebuilt BMT resource for flowcontrol and proofs
blocksize int // segment size (size of hash) also for hash.Hash
count int // segment count
size int // for hash.Hash same as hashsize
cur int // cursor position for righmost currently open chunk
segment []byte // the rightmost open segment (not complete)
depth int // index of last level
result chan []byte // result channel
hash []byte // to record the result
max int32 // max segments for SegmentWriter interface
blockLength []byte // The block length that needes to be added in Sum
}
// New creates a reusable Hasher
// implements the hash.Hash interface
// pulls a new Tree from a resource pool for hashing each chunk
func New(p *TreePool) *Hasher {
return &Hasher{
pool: p,
depth: depth(p.SegmentCount),
size: p.SegmentSize,
blocksize: p.SegmentSize,
count: p.SegmentCount,
result: make(chan []byte),
}
}
// Node is a reuseable segment hasher representing a node in a BMT
// it allows for continued writes after a Sum
// and is left in completely reusable state after Reset
type Node struct {
level, index int // position of node for information/logging only
initial bool // first and last node
root bool // whether the node is root to a smaller BMT
isLeft bool // whether it is left side of the parent double segment
unbalanced bool // indicates if a node has only the left segment
parent *Node // BMT connections
state int32 // atomic increment impl concurrent boolean toggle
left, right []byte
}
// NewNode constructor for segment hasher nodes in the BMT
func NewNode(level, index int, parent *Node) *Node {
return &Node{
parent: parent,
level: level,
index: index,
initial: index == 0,
isLeft: index%2 == 0,
}
}
// TreePool provides a pool of Trees used as resources by Hasher
// a Tree popped from the pool is guaranteed to have clean state
// for hashing a new chunk
// Hasher Reset releases the Tree to the pool
type TreePool struct {
lock sync.Mutex
c chan *Tree
hasher BaseHasher
SegmentSize int
SegmentCount int
Capacity int
count int
}
// NewTreePool creates a Tree pool with hasher, segment size, segment count and capacity
// on GetTree it reuses free Trees or creates a new one if size is not reached
func NewTreePool(hasher BaseHasher, segmentCount, capacity int) *TreePool {
return &TreePool{
c: make(chan *Tree, capacity),
hasher: hasher,
SegmentSize: hasher().Size(),
SegmentCount: segmentCount,
Capacity: capacity,
}
}
// Drain drains the pool uptil it has no more than n resources
func (self *TreePool) Drain(n int) {
self.lock.Lock()
defer self.lock.Unlock()
for len(self.c) > n {
<-self.c
self.count--
}
}
// Reserve is blocking until it returns an available Tree
// it reuses free Trees or creates a new one if size is not reached
func (self *TreePool) Reserve() *Tree {
self.lock.Lock()
defer self.lock.Unlock()
var t *Tree
if self.count == self.Capacity {
return <-self.c
}
select {
case t = <-self.c:
default:
t = NewTree(self.hasher, self.SegmentSize, self.SegmentCount)
self.count++
}
return t
}
// Release gives back a Tree to the pool.
// This Tree is guaranteed to be in reusable state
// does not need locking
func (self *TreePool) Release(t *Tree) {
self.c <- t // can never fail but...
}
// Tree is a reusable control structure representing a BMT
// organised in a binary tree
// Hasher uses a TreePool to pick one for each chunk hash
// the Tree is 'locked' while not in the pool
type Tree struct {
leaves []*Node
}
// Draw draws the BMT (badly)
func (self *Tree) Draw(hash []byte, d int) string {
var left, right []string
var anc []*Node
for i, n := range self.leaves {
left = append(left, fmt.Sprintf("%v", hashstr(n.left)))
if i%2 == 0 {
anc = append(anc, n.parent)
}
right = append(right, fmt.Sprintf("%v", hashstr(n.right)))
}
anc = self.leaves
var hashes [][]string
for l := 0; len(anc) > 0; l++ {
var nodes []*Node
hash := []string{""}
for i, n := range anc {
hash = append(hash, fmt.Sprintf("%v|%v", hashstr(n.left), hashstr(n.right)))
if i%2 == 0 && n.parent != nil {
nodes = append(nodes, n.parent)
}
}
hash = append(hash, "")
hashes = append(hashes, hash)
anc = nodes
}
hashes = append(hashes, []string{"", fmt.Sprintf("%v", hashstr(hash)), ""})
total := 60
del := " "
var rows []string
for i := len(hashes) - 1; i >= 0; i-- {
var textlen int
hash := hashes[i]
for _, s := range hash {
textlen += len(s)
}
if total < textlen {
total = textlen + len(hash)
}
delsize := (total - textlen) / (len(hash) - 1)
if delsize > len(del) {
delsize = len(del)
}
row := fmt.Sprintf("%v: %v", len(hashes)-i-1, strings.Join(hash, del[:delsize]))
rows = append(rows, row)
}
rows = append(rows, strings.Join(left, " "))
rows = append(rows, strings.Join(right, " "))
return strings.Join(rows, "\n") + "\n"
}
// NewTree initialises the Tree by building up the nodes of a BMT
// segment size is stipulated to be the size of the hash
// segmentCount needs to be positive integer and does not need to be
// a power of two and can even be an odd number
// segmentSize * segmentCount determines the maximum chunk size
// hashed using the tree
func NewTree(hasher BaseHasher, segmentSize, segmentCount int) *Tree {
n := NewNode(0, 0, nil)
n.root = true
prevlevel := []*Node{n}
// iterate over levels and creates 2^level nodes
level := 1
count := 2
for d := 1; d <= depth(segmentCount); d++ {
nodes := make([]*Node, count)
for i := 0; i < len(nodes); i++ {
parent := prevlevel[i/2]
t := NewNode(level, i, parent)
nodes[i] = t
}
prevlevel = nodes
level++
count *= 2
}
// the datanode level is the nodes on the last level where
return &Tree{
leaves: prevlevel,
}
}
// methods needed by hash.Hash
// Size returns the size
func (self *Hasher) Size() int {
return self.size
}
// BlockSize returns the block size
func (self *Hasher) BlockSize() int {
return self.blocksize
}
// Sum returns the hash of the buffer
// hash.Hash interface Sum method appends the byte slice to the underlying
// data before it calculates and returns the hash of the chunk
func (self *Hasher) Sum(b []byte) (r []byte) {
t := self.bmt
i := self.cur
n := t.leaves[i]
j := i
// must run strictly before all nodes calculate
// datanodes are guaranteed to have a parent
if len(self.segment) > self.size && i > 0 && n.parent != nil {
n = n.parent
} else {
i *= 2
}
d := self.finalise(n, i)
self.writeSegment(j, self.segment, d)
c := <-self.result
self.releaseTree()
// sha3(length + BMT(pure_chunk))
if self.blockLength == nil {
return c
}
res := self.pool.hasher()
res.Reset()
res.Write(self.blockLength)
res.Write(c)
return res.Sum(nil)
}
// Hasher implements the SwarmHash interface
// Hash waits for the hasher result and returns it
// caller must call this on a BMT Hasher being written to
func (self *Hasher) Hash() []byte {
return <-self.result
}
// Hasher implements the io.Writer interface
// Write fills the buffer to hash
// with every full segment complete launches a hasher go routine
// that shoots up the BMT
func (self *Hasher) Write(b []byte) (int, error) {
l := len(b)
if l <= 0 {
return 0, nil
}
s := self.segment
i := self.cur
count := (self.count + 1) / 2
need := self.count*self.size - self.cur*2*self.size
size := self.size
if need > size {
size *= 2
}
if l < need {
need = l
}
// calculate missing bit to complete current open segment
rest := size - len(s)
if need < rest {
rest = need
}
s = append(s, b[:rest]...)
need -= rest
// read full segments and the last possibly partial segment
for need > 0 && i < count-1 {
// push all finished chunks we read
self.writeSegment(i, s, self.depth)
need -= size
if need < 0 {
size += need
}
s = b[rest : rest+size]
rest += size
i++
}
self.segment = s
self.cur = i
// otherwise, we can assume len(s) == 0, so all buffer is read and chunk is not yet full
return l, nil
}
// Hasher implements the io.ReaderFrom interface
// ReadFrom reads from io.Reader and appends to the data to hash using Write
// it reads so that chunk to hash is maximum length or reader reaches EOF
// caller must Reset the hasher prior to call
func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
bufsize := self.size*self.count - self.size*self.cur - len(self.segment)
buf := make([]byte, bufsize)
var read int
for {
var n int
n, err = r.Read(buf)
read += n
if err == io.EOF || read == len(buf) {
hash := self.Sum(buf[:n])
if read == len(buf) {
err = NewEOC(hash)
}
break
}
if err != nil {
break
}
n, err = self.Write(buf[:n])
if err != nil {
break
}
}
return int64(read), err
}
// Reset needs to be called before writing to the hasher
func (self *Hasher) Reset() {
self.getTree()
self.blockLength = nil
}
// Hasher implements the SwarmHash interface
// ResetWithLength needs to be called before writing to the hasher
// the argument is supposed to be the byte slice binary representation of
// the legth of the data subsumed under the hash
func (self *Hasher) ResetWithLength(l []byte) {
self.Reset()
self.blockLength = l
}
// Release gives back the Tree to the pool whereby it unlocks
// it resets tree, segment and index
func (self *Hasher) releaseTree() {
if self.bmt != nil {
n := self.bmt.leaves[self.cur]
for ; n != nil; n = n.parent {
n.unbalanced = false
if n.parent != nil {
n.root = false
}
}
self.pool.Release(self.bmt)
self.bmt = nil
}
self.cur = 0
self.segment = nil
}
func (self *Hasher) writeSegment(i int, s []byte, d int) {
h := self.pool.hasher()
n := self.bmt.leaves[i]
if len(s) > self.size && n.parent != nil {
go func() {
h.Reset()
h.Write(s)
s = h.Sum(nil)
if n.root {
self.result <- s
return
}
self.run(n.parent, h, d, n.index, s)
}()
return
}
go self.run(n, h, d, i*2, s)
}
func (self *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) {
isLeft := i%2 == 0
for {
if isLeft {
n.left = s
} else {
n.right = s
}
if !n.unbalanced && n.toggle() {
return
}
if !n.unbalanced || !isLeft || i == 0 && d == 0 {
h.Reset()
h.Write(n.left)
h.Write(n.right)
s = h.Sum(nil)
} else {
s = append(n.left, n.right...)
}
self.hash = s
if n.root {
self.result <- s
return
}
isLeft = n.isLeft
n = n.parent
i++
}
}
// getTree obtains a BMT resource by reserving one from the pool
func (self *Hasher) getTree() *Tree {
if self.bmt != nil {
return self.bmt
}
t := self.pool.Reserve()
self.bmt = t
return t
}
// atomic bool toggle implementing a concurrent reusable 2-state object
// atomic addint with %2 implements atomic bool toggle
// it returns true if the toggler just put it in the active/waiting state
func (self *Node) toggle() bool {
return atomic.AddInt32(&self.state, 1)%2 == 1
}
func hashstr(b []byte) string {
end := len(b)
if end > 4 {
end = 4
}
return fmt.Sprintf("%x", b[:end])
}
func depth(n int) (d int) {
for l := (n - 1) / 2; l > 0; l /= 2 {
d++
}
return d
}
// finalise is following the zigzags on the tree belonging
// to the final datasegment
func (self *Hasher) finalise(n *Node, i int) (d int) {
isLeft := i%2 == 0
for {
// when the final segment's path is going via left segments
// the incoming data is pushed to the parent upon pulling the left
// we do not need toogle the state since this condition is
// detectable
n.unbalanced = isLeft
n.right = nil
if n.initial {
n.root = true
return d
}
isLeft = n.isLeft
n = n.parent
d++
}
}
// EOC (end of chunk) implements the error interface
type EOC struct {
Hash []byte // read the hash of the chunk off the error
}
// Error returns the error string
func (self *EOC) Error() string {
return fmt.Sprintf("hasher limit reached, chunk hash: %x", self.Hash)
}
// NewEOC creates new end of chunk error with the hash
func NewEOC(hash []byte) *EOC {
return &EOC{hash}
}

85
bmt/bmt_r.go Normal file
View File

@@ -0,0 +1,85 @@
// Copyright 2017 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/>.
// simple nonconcurrent reference implementation for hashsize segment based
// Binary Merkle tree hash on arbitrary but fixed maximum chunksize
//
// This implementation does not take advantage of any paralellisms and uses
// far more memory than necessary, but it is easy to see that it is correct.
// It can be used for generating test cases for optimized implementations.
// see testBMTHasherCorrectness function in bmt_test.go
package bmt
import (
"hash"
)
// RefHasher is the non-optimized easy to read reference implementation of BMT
type RefHasher struct {
span int
section int
cap int
h hash.Hash
}
// NewRefHasher returns a new RefHasher
func NewRefHasher(hasher BaseHasher, count int) *RefHasher {
h := hasher()
hashsize := h.Size()
maxsize := hashsize * count
c := 2
for ; c < count; c *= 2 {
}
if c > 2 {
c /= 2
}
return &RefHasher{
section: 2 * hashsize,
span: c * hashsize,
cap: maxsize,
h: h,
}
}
// Hash returns the BMT hash of the byte slice
// implements the SwarmHash interface
func (rh *RefHasher) Hash(d []byte) []byte {
if len(d) > rh.cap {
d = d[:rh.cap]
}
return rh.hash(d, rh.span)
}
func (rh *RefHasher) hash(d []byte, s int) []byte {
l := len(d)
left := d
var right []byte
if l > rh.section {
for ; s >= l; s /= 2 {
}
left = rh.hash(d[:s], s)
right = d[s:]
if l-s > rh.section/2 {
right = rh.hash(right, s)
}
}
defer rh.h.Reset()
rh.h.Write(left)
rh.h.Write(right)
h := rh.h.Sum(nil)
return h
}

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