Merge branch 'develop' into ui

This commit is contained in:
Alexandre Van de Sande 2015-03-04 10:04:07 -03:00
commit 5f25c117eb
65 changed files with 1444 additions and 1367 deletions

View File

@ -1,8 +1,8 @@
language: go
go:
- 1.4.1
- 1.4.2
before_install:
- sudo add-apt-repository ppa:beineri/opt-qt54 -y
- sudo add-apt-repository ppa:beineri/opt-qt541 -y
- sudo apt-get update -qq
- sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine
install:

View File

@ -1,4 +1,4 @@
FROM ubuntu:14.04.1
FROM ubuntu:14.04.2
## Environment setup
ENV HOME /root
@ -12,22 +12,22 @@ ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y git mercurial build-essential software-properties-common wget pkg-config libgmp3-dev libreadline6-dev libpcre3-dev libpcre++-dev
## Install Qt5.4 (not required for CLI)
# RUN add-apt-repository ppa:beineri/opt-qt54-trusty -y
## Install Qt5.4.1 (not required for CLI)
# RUN add-apt-repository ppa:beineri/opt-qt541-trusty -y
# RUN apt-get update -y
# RUN apt-get install -y qt54quickcontrols qt54webengine mesa-common-dev libglu1-mesa-dev
# ENV PKG_CONFIG_PATH /opt/qt54/lib/pkgconfig
# Install Golang
RUN wget https://storage.googleapis.com/golang/go1.4.1.linux-amd64.tar.gz
RUN wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz
RUN tar -C /usr/local -xzf go*.tar.gz && go version
# this is a workaround, to make sure that docker's cache is invalidated whenever the git repo changes
ADD https://api.github.com/repos/ethereum/go-ethereum/git/refs/heads/develop file_does_not_exist
## Fetch and install go-ethereum
RUN go get -v github.com/tools/godep
RUN go get -v -d github.com/ethereum/go-ethereum/...
RUN go get github.com/tools/godep
RUN go get -d github.com/ethereum/go-ethereum/...
WORKDIR $GOPATH/src/github.com/ethereum/go-ethereum
RUN git checkout develop
RUN godep restore

11
Godeps/Godeps.json generated
View File

@ -1,15 +1,10 @@
{
"ImportPath": "github.com/ethereum/go-ethereum",
"GoVersion": "go1.4.1",
"GoVersion": "go1.4.2",
"Packages": [
"./..."
],
"Deps": [
{
"ImportPath": "bitbucket.org/kardianos/osext",
"Comment": "null-13",
"Rev": "5d3ddcf53a508cc2f7404eaebf546ef2cb5cdb6e"
},
{
"ImportPath": "code.google.com/p/go-uuid/uuid",
"Comment": "null-12",
@ -37,6 +32,10 @@
"ImportPath": "github.com/jackpal/go-nat-pmp",
"Rev": "a45aa3d54aef73b504e15eb71bea0e5565b5e6e1"
},
{
"ImportPath": "github.com/kardianos/osext",
"Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a"
},
{
"ImportPath": "github.com/obscuren/otto",
"Rev": "cf13cc4228c5e5ce0fe27a7aea90bc10091c4f19"

View File

@ -1,20 +0,0 @@
Copyright (c) 2012 Daniel Theophanes
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

View File

@ -0,0 +1,27 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,14 @@
### Extensions to the "os" package.
## Find the current Executable and ExecutableFolder.
There is sometimes utility in finding the current executable file
that is running. This can be used for upgrading the current executable
or finding resources located relative to the executable file.
Multi-platform and supports:
* Linux
* OS X
* Windows
* Plan 9
* BSDs.

View File

@ -25,8 +25,3 @@ func ExecutableFolder() (string, error) {
folder, _ := filepath.Split(p)
return folder, nil
}
// Depricated. Same as Executable().
func GetExePath() (exePath string, err error) {
return Executable()
}

View File

@ -5,9 +5,9 @@
package osext
import (
"syscall"
"os"
"strconv"
"syscall"
)
func executable() (string, error) {

View File

@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux netbsd openbsd
// +build linux netbsd openbsd solaris dragonfly
package osext
import (
"errors"
"fmt"
"os"
"runtime"
)
@ -18,8 +19,10 @@ func executable() (string, error) {
return os.Readlink("/proc/self/exe")
case "netbsd":
return os.Readlink("/proc/curproc/exe")
case "openbsd":
case "openbsd", "dragonfly":
return os.Readlink("/proc/curproc/file")
case "solaris":
return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid()))
}
return "", errors.New("ExecPath not implemented for " + runtime.GOOS)
}

112
README.md
View File

@ -24,7 +24,25 @@ Ethereum (CLI):
`go get github.com/ethereum/go-ethereum/cmd/ethereum`
For further, detailed, build instruction please see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go))
As of POC-8, go-ethereum uses [Godep](https://github.com/tools/godep) to manage dependencies. Assuming you have [your environment all set up](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)), switch to the go-ethereum repository root folder, and build/install the executable you need:
Mist (GUI):
```
godep go build -v ./cmd/mist
```
Ethereum (CLI):
```
godep go build -v ./cmd/ethereum
```
Instead of `build`, you can use `install` which will also install the resulting binary.
For prerequisites and detailed build instructions please see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go))
If you intend to develop on go-ethereum, check the [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
Automated (dev) builds
======================
@ -34,97 +52,47 @@ Automated (dev) builds
* [Windows] Coming soon™
* [Linux] Coming soon™
Binaries
========
Executables
===========
Go Ethereum comes with several binaries found in
[cmd](https://github.com/ethereum/go-ethereum/tree/master/cmd):
Go Ethereum comes with several wrappers/executables found in
[the `cmd` directory](https://github.com/ethereum/go-ethereum/tree/develop/cmd):
* `mist` Official Ethereum Browser
* `ethereum` Ethereum CLI
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suit:
* `mist` Official Ethereum Browser (ethereum GUI client)
* `ethereum` Ethereum CLI (ethereum command line interface client)
* `bootnode` runs a bootstrap node for the Discovery Protocol
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suite:
`cat file | ethtest`.
* `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
10000 -price 0 -dump`. See `-h` for a detailed description.
* `rlpdump` converts a rlp stream to `interface{}`.
* `peerserver` simple P2P (noi-ethereum) peer server.
* `disasm` disassembles EVM code: `echo "6001" | disasm`
* `rlpdump` converts a rlp stream to `interface{}`.
General command line options
Command line options
============================
Both `mist` and `ethereum` can be configured via command line options, environment variables and config files.
To get the options available:
```
== Shared between ethereum and Mist ==
= Settings
-id Set the custom identifier of the client (shows up on other clients)
-port Port on which the server will accept incomming connections
-upnp Enable UPnP
-maxpeer Desired amount of peers
-rpc Start JSON RPC
-dir Data directory used to store configs and databases
= Utility
-h This
-import Import a private key
-genaddr Generates a new address and private key (destructive action)
-dump Dump a specific state of a block to stdout given the -number or -hash
-difftool Supress all output and prints VM output to stdout
-diff vm=only vm output, all=all output including state storage
Ethereum only
ethereum [options] [filename]
-js Start the JavaScript REPL
filename Load the given file and interpret as JavaScript
-m Start mining blocks
== Mist only ==
-asset_path absolute path to GUI assets directory
ethereum -help
```
For further details on options, see the [wiki](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)
Contribution
============
If you'd like to contribute to Ethereum please fork, fix, commit and
If you'd like to contribute to go-ethereum please fork, fix, commit and
send a pull request. Commits who do not comply with the coding standards
are ignored (use gofmt!). If you send pull requests make absolute sure that you
commit on the `develop` branch and that you do not merge to master.
Commits that are directly based on master are simply ignored.
For dependency management, we use [godep](https://github.com/tools/godep). After installing with `go get github.com/tools/godep`, run `godep restore` to ensure that changes to other repositories do not break the build. To update a dependency version (for example, to include a new upstream fix), run `go get -u <foo/bar>` then `godep update <foo/...>`. To track a new dependency, add it to the project as normal than run `godep save ./...`. Changes to the Godeps folder should be manually verified then commited.
For dependency management, we use [godep](https://github.com/tools/godep). After installing with `go get github.com/tools/godep`, run `godep restore` to ensure that changes to other repositories do not break the build. To update a dependency version (for example, to include a new upstream fix), run `go get -u <foo/bar>` then `godep update <foo/...>`. To track a new dependency, add it to the project as normal than run `godep save ./...`. Changes to the [Godeps folder](https://github.com/ethereum/go-ethereum/tree/develop/Godeps): should be manually verified then commited.
To make life easier try [git flow](http://nvie.com/posts/a-successful-git-branching-model/) it sets
this all up and streamlines your work flow.
Coding standards
================
Sources should be formatted according to the [Go Formatting
Style](http://golang.org/doc/effective_go.html#formatting).
Unless structs fields are supposed to be directly accesible, provide
Getters and hide the fields through Go's exporting facility.
When you comment put meaningful comments. Describe in detail what you
want to achieve.
*wrong*
```go
// Check if the value at x is greater than y
if x > y {
// It's greater!
}
```
Everyone reading the source probably know what you wanted to achieve
with above code. Those are **not** meaningful comments.
While the project isn't 100% tested I want you to write tests non the
less. I haven't got time to evaluate everyone's code in detail so I
expect you to write tests for me so I don't have to test your code
manually. (If you want to contribute by just writing tests that's fine
too!)
To make life easier try [git flow](http://nvie.com/posts/a-successful-git-branching-model/) it sets this all up and streamlines your work flow.
See [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)

View File

@ -34,9 +34,16 @@ package accounts
import (
crand "crypto/rand"
"errors"
"sync"
"time"
"github.com/ethereum/go-ethereum/crypto"
)
var ErrLocked = errors.New("account is locked; please request passphrase")
// TODO: better name for this struct?
type Account struct {
Address []byte
@ -44,23 +51,45 @@ type Account struct {
type AccountManager struct {
keyStore crypto.KeyStore2
unlockedKeys map[string]crypto.Key
unlockMilliseconds time.Duration
mutex sync.RWMutex
}
// TODO: get key by addr - modify KeyStore2 GetKey to work with addr
// TODO: pass through passphrase for APIs which require access to private key?
func NewAccountManager(keyStore crypto.KeyStore2) AccountManager {
func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Duration) AccountManager {
keysMap := make(map[string]crypto.Key)
am := &AccountManager{
keyStore: keyStore,
unlockedKeys: keysMap,
unlockMilliseconds: unlockMilliseconds,
}
return *am
}
func (am *AccountManager) Sign(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) {
func (am AccountManager) DeleteAccount(address []byte, auth string) error {
return am.keyStore.DeleteKey(address, auth)
}
func (am *AccountManager) Sign(fromAccount *Account, toSign []byte) (signature []byte, err error) {
am.mutex.RLock()
unlockedKey := am.unlockedKeys[string(fromAccount.Address)]
am.mutex.RUnlock()
if unlockedKey.Address == nil {
return nil, ErrLocked
}
signature, err = crypto.Sign(toSign, unlockedKey.PrivateKey)
return signature, err
}
func (am *AccountManager) SignLocked(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) {
key, err := am.keyStore.GetKey(fromAccount.Address, keyAuth)
if err != nil {
return nil, err
}
am.mutex.RLock()
am.unlockedKeys[string(fromAccount.Address)] = *key
am.mutex.RUnlock()
go unlockLater(am, fromAccount.Address)
signature, err = crypto.Sign(toSign, key.PrivateKey)
return signature, err
}
@ -76,8 +105,6 @@ func (am AccountManager) NewAccount(auth string) (*Account, error) {
return ua, err
}
// set of accounts == set of keys in given key store
// TODO: do we need persistence of accounts as well?
func (am *AccountManager) Accounts() ([]Account, error) {
addresses, err := am.keyStore.GetKeyAddresses()
if err != nil {
@ -93,3 +120,13 @@ func (am *AccountManager) Accounts() ([]Account, error) {
}
return accounts, err
}
func unlockLater(am *AccountManager, addr []byte) {
select {
case <-time.After(time.Millisecond * am.unlockMilliseconds):
}
am.mutex.RLock()
// TODO: how do we know the key is actually gone from memory?
delete(am.unlockedKeys, string(addr))
am.mutex.RUnlock()
}

View File

@ -5,16 +5,78 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/randentropy"
"github.com/ethereum/go-ethereum/ethutil"
"time"
)
func TestAccountManager(t *testing.T) {
ks := crypto.NewKeyStorePlain(crypto.DefaultDataDir())
am := NewAccountManager(ks)
ks := crypto.NewKeyStorePlain(ethutil.DefaultDataDir() + "/testaccounts")
am := NewAccountManager(ks, 100)
pass := "" // not used but required by API
a1, err := am.NewAccount(pass)
toSign := randentropy.GetEntropyCSPRNG(32)
_, err = am.Sign(a1, pass, toSign)
_, err = am.SignLocked(a1, pass, toSign)
if err != nil {
t.Fatal(err)
}
// Cleanup
time.Sleep(time.Millisecond * 150) // wait for locking
accounts, err := am.Accounts()
if err != nil {
t.Fatal(err)
}
for _, account := range accounts {
err := am.DeleteAccount(account.Address, pass)
if err != nil {
t.Fatal(err)
}
}
}
func TestAccountManagerLocking(t *testing.T) {
ks := crypto.NewKeyStorePassphrase(ethutil.DefaultDataDir() + "/testaccounts")
am := NewAccountManager(ks, 200)
pass := "foo"
a1, err := am.NewAccount(pass)
toSign := randentropy.GetEntropyCSPRNG(32)
// Signing without passphrase fails because account is locked
_, err = am.Sign(a1, toSign)
if err != ErrLocked {
t.Fatal(err)
}
// Signing with passphrase works
_, err = am.SignLocked(a1, pass, toSign)
if err != nil {
t.Fatal(err)
}
// Signing without passphrase works because account is temp unlocked
_, err = am.Sign(a1, toSign)
if err != nil {
t.Fatal(err)
}
// Signing without passphrase fails after automatic locking
time.Sleep(time.Millisecond * time.Duration(250))
_, err = am.Sign(a1, toSign)
if err != ErrLocked {
t.Fatal(err)
}
// Cleanup
accounts, err := am.Accounts()
if err != nil {
t.Fatal(err)
}
for _, account := range accounts {
err := am.DeleteAccount(account.Address, pass)
if err != nil {
t.Fatal(err)
}
}
}

View File

@ -26,10 +26,11 @@ import (
"fmt"
"log"
"os"
"os/user"
"path"
"runtime"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/vm"
@ -43,8 +44,8 @@ var (
KeyStore string
StartRpc bool
StartWebSockets bool
RpcListenAddress string
RpcPort int
WsPort int
OutboundPort string
ShowGenesis bool
AddPeer string
@ -70,6 +71,7 @@ var (
SHH bool
Dial bool
PrintVersion bool
MinerThreads int
)
// flags specific to cli client
@ -79,12 +81,7 @@ var (
InputFile string
)
func defaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereum")
}
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini")
func Init() {
// TODO: move common flag processing to cmd/util
@ -96,22 +93,21 @@ func Init() {
flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug")
flag.StringVar(&Identifier, "id", "", "Custom client identifier")
flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)")
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file")
flag.StringVar(&RpcListenAddress, "rpcaddr", "127.0.0.1", "address for json-rpc server to listen on")
flag.IntVar(&RpcPort, "rpcport", 8545, "port to start json-rpc server on")
flag.IntVar(&WsPort, "wsport", 40404, "port to start websocket rpc server on")
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)")
flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use")
flag.StringVar(&Datadir, "datadir", ethutil.DefaultDataDir(), "specifies the datadir to use")
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
flag.StringVar(&LogFormat, "logformat", "std", "logformat: std,raw)")
flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5 (= silent,error,warn,info,debug,debug detail)")
flag.StringVar(&LogFormat, "logformat", "std", "logformat: std,raw")
flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
flag.BoolVar(&ShowGenesis, "genesis", false, "Dump the genesis block")
@ -121,9 +117,10 @@ func Init() {
flag.StringVar(&DumpHash, "hash", "", "specify arg in hex")
flag.IntVar(&DumpNumber, "number", -1, "specify arg in number")
flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
flag.BoolVar(&StartMining, "mine", false, "start mining")
flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")
flag.BoolVar(&PrintVersion, "version", false, "prints version number")
flag.IntVar(&MinerThreads, "minerthreads", runtime.NumCPU(), "number of miner threads")
// Network stuff
var (
@ -140,6 +137,12 @@ func Init() {
flag.Parse()
// When the javascript console is started log to a file instead
// of stdout
if StartJsConsole {
LogFile = path.Join(Datadir, "ethereum.log")
}
var err error
if NAT, err = nat.Parse(*natstr); err != nil {
log.Fatalf("-nat: %v", err)

View File

@ -37,7 +37,7 @@ import (
const (
ClientIdentifier = "Ethereum(G)"
Version = "0.8.5"
Version = "0.8.6"
)
var clilogger = logger.NewLogger("CLI")
@ -76,6 +76,7 @@ func main() {
Dial: Dial,
BootNodes: BootNodes,
NodeKey: NodeKey,
MinerThreads: MinerThreads,
})
if err != nil {
@ -113,10 +114,6 @@ func main() {
return
}
if StartMining {
utils.StartMining(ethereum)
}
if len(ImportChain) > 0 {
start := time.Now()
err := utils.ImportChain(ethereum, ImportChain)
@ -128,15 +125,17 @@ func main() {
}
if StartRpc {
utils.StartRpc(ethereum, RpcPort)
}
if StartWebSockets {
utils.StartWebSockets(ethereum, WsPort)
utils.StartRpc(ethereum, RpcListenAddress, RpcPort)
}
utils.StartEthereum(ethereum)
fmt.Printf("Welcome to the FRONTIER\n")
if StartMining {
ethereum.Miner().Start()
}
if StartJsConsole {
InitJsConsole(ethereum)
} else if len(InputFile) > 0 {

View File

@ -60,6 +60,7 @@ func (self *JSRepl) Start() {
if !self.running {
self.running = true
repllogger.Infoln("init JS Console")
reader := bufio.NewReader(self.history)
for {
line, err := reader.ReadString('\n')

View File

@ -19,6 +19,7 @@
<span>Amount:</span>
<input type="text" id="amount" style="width:200px">
<button onclick="transact()">Send</button>
<span id="message"></span>
</div>
<hr>
@ -95,17 +96,28 @@
}
function transact() {
var to = document.querySelector("#address").value;
if( to.length == 0 ) {
var to = document.querySelector("#address");
if( to.value.length == 0 ) {
to = "0x4205b06c2cfa0e30359edcab94543266cb6fa1d3";
} else {
to = "0x"+to;
if (to.value.substr(0,2) != "0x")
to.value = "0x"+to.value;
}
var value = parseInt( document.querySelector("#amount").value );
console.log("transact: ", to, " => ", value)
var value = document.querySelector("#amount");
var amount = parseInt( value.value );
console.log("transact: ", to.value, " => ", amount)
contract.send( to, value );
contract.send( to.value, amount );
to.value = "";
value.value = "";
var message = document.querySelector("#message")
message.innerHTML = "Submitted";
setTimeout(function() {
message.innerHTML = "";
}, 1000);
}
refresh();

View File

@ -62,6 +62,8 @@
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545'));
eth.defaultBlock = -2
document.querySelector("#number").innerHTML = eth.number;
document.querySelector("#coinbase").innerHTML = eth.coinbase
document.querySelector("#peer_count").innerHTML = eth.peerCount;
@ -75,6 +77,7 @@
document.querySelector("#number").innerHTML = eth.number;
});
</script>
</html>

View File

@ -53,7 +53,6 @@ var inputTypes = types.inputTypes();
/// @returns bytes representation of input params
var formatInput = function (inputs, params) {
var bytes = "";
var padding = c.ETH_PADDING * 2;
/// first we iterate in search for dynamic
inputs.forEach(function (input, index) {
@ -110,6 +109,7 @@ var formatOutput = function (outs, output) {
output = output.slice(dynamicPartLength);
outs.forEach(function (out, i) {
/*jshint maxcomplexity:6 */
var typeMatch = false;
for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
typeMatch = outputTypes[j].type(outs[i].type);
@ -210,7 +210,7 @@ module.exports = {
};
},{"./const":2,"./formatters":6,"./types":11,"./utils":12,"./web3":13}],2:[function(require,module,exports){
},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -264,7 +264,8 @@ module.exports = {
ETH_PADDING: 32,
ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },
ETH_POLLING_TIMEOUT: 1000
};
@ -340,6 +341,7 @@ var addFunctionsToContract = function (contract, desc, address) {
var typeName = utils.extractTypeName(method.name);
var impl = function () {
/*jshint maxcomplexity:7 */
var params = Array.prototype.slice.call(arguments);
var signature = abi.signatureFromAscii(method.name);
var parsed = inputParser[displayName][typeName].apply(null, params);
@ -416,11 +418,11 @@ var addEventsToContract = function (contract, desc, address) {
var signature = abi.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, signature, e);
var o = event.apply(null, params);
o._onWatchEventResult = function (data) {
var outputFormatter = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.watch(o);
return web3.eth.watch(o, undefined, undefined, outputFormatter);
};
// this property should be used by eth.filter to check if object is an event
@ -487,7 +489,131 @@ var contract = function (address, desc) {
module.exports = contract;
},{"./abi":1,"./event":4,"./utils":12,"./web3":13}],4:[function(require,module,exports){
},{"./abi":1,"./event":6,"./utils":15,"./web3":17}],4:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js 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.
ethereum.js 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 ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file db.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
/// @returns an array of objects describing web3.db api methods
var methods = function () {
return [
{ name: 'put', call: 'db_put' },
{ name: 'get', call: 'db_get' },
{ name: 'putString', call: 'db_putString' },
{ name: 'getString', call: 'db_getString' }
];
};
module.exports = {
methods: methods
};
},{}],5:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js 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.
ethereum.js 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 ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file eth.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
/// @returns an array of objects describing web3.eth api methods
var methods = function () {
var blockCall = function (args) {
return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
};
var transactionCall = function (args) {
return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber';
};
var uncleCall = function (args) {
return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber';
};
var transactionCountCall = function (args) {
return typeof args[0] === "string" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber';
};
var uncleCountCall = function (args) {
return typeof args[0] === "string" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber';
};
return [
{ name: 'balanceAt', call: 'eth_balanceAt' },
{ name: 'stateAt', call: 'eth_stateAt' },
{ name: 'storageAt', call: 'eth_storageAt' },
{ name: 'countAt', call: 'eth_countAt'},
{ name: 'codeAt', call: 'eth_codeAt' },
{ name: 'transact', call: 'eth_transact' },
{ name: 'call', call: 'eth_call' },
{ name: 'block', call: blockCall },
{ name: 'transaction', call: transactionCall },
{ name: 'uncle', call: uncleCall },
{ name: 'compilers', call: 'eth_compilers' },
{ name: 'flush', call: 'eth_flush' },
{ name: 'lll', call: 'eth_lll' },
{ name: 'solidity', call: 'eth_solidity' },
{ name: 'serpent', call: 'eth_serpent' },
{ name: 'logs', call: 'eth_logs' },
{ name: 'transactionCount', call: transactionCountCall },
{ name: 'uncleCount', call: uncleCountCall }
];
};
/// @returns an array of objects describing web3.eth api properties
var properties = function () {
return [
{ name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },
{ name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },
{ name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },
{ name: 'gasPrice', getter: 'eth_gasPrice' },
{ name: 'accounts', getter: 'eth_accounts' },
{ name: 'peerCount', getter: 'eth_peerCount' },
{ name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },
{ name: 'number', getter: 'eth_number'}
];
};
module.exports = {
methods: methods,
properties: properties
};
},{}],6:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -571,9 +697,9 @@ var getArgumentsObject = function (inputs, indexed, notIndexed) {
return inputs.reduce(function (acc, current) {
var value;
if (current.indexed)
value = indexed.splice(0, 1)[0];
value = indexedCopy.splice(0, 1)[0];
else
value = notIndexed.splice(0, 1)[0];
value = notIndexedCopy.splice(0, 1)[0];
acc[current.name] = value;
return acc;
@ -589,6 +715,7 @@ var outputParser = function (event) {
args: {}
};
output.topics = output.topic; // fallback for go-ethereum
if (!output.topic) {
return result;
}
@ -624,7 +751,7 @@ module.exports = {
};
},{"./abi":1,"./utils":12}],5:[function(require,module,exports){
},{"./abi":1,"./utils":15}],7:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -650,24 +777,33 @@ module.exports = {
* @date 2014
*/
var web3 = require('./web3'); // jshint ignore:line
/// Should be called to check if filter implementation is valid
/// @returns true if it is, otherwise false
var implementationIsValid = function (i) {
return !!i &&
typeof i.newFilter === 'function' &&
typeof i.getMessages === 'function' &&
typeof i.uninstallFilter === 'function' &&
typeof i.startPolling === 'function' &&
typeof i.stopPolling === 'function';
};
/// should be used when we want to watch something
/// it's using inner polling mechanism and is notified about changes
/// TODO: change 'options' name cause it may be not the best matching one, since we have events
var Filter = function(options, impl) {
if (typeof options !== "string") {
// topics property is deprecated, warn about it!
if (options.topics) {
console.warn('"topics" is deprecated, use "topic" instead');
/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones
/// @param should be string or object
/// @returns options string or object
var getOptions = function (options) {
if (typeof options === 'string') {
return options;
}
this._onWatchResult = options._onWatchEventResult;
options = options || {};
if (options.topics) {
console.warn('"topics" is deprecated, is "topic" instead');
}
// evaluate lazy properties
options = {
return {
to: options.to,
topic: options.topic,
earliest: options.earliest,
@ -676,58 +812,61 @@ var Filter = function(options, impl) {
skip: options.skip,
address: options.address
};
};
/// Should be used when we want to watch something
/// it's using inner polling mechanism and is notified about changes
/// @param options are filter options
/// @param implementation, an abstract polling implementation
/// @param formatter (optional), callback function which formats output before 'real' callback
var filter = function(options, implementation, formatter) {
if (!implementationIsValid(implementation)) {
console.error('filter implemenation is invalid');
return;
}
this.impl = impl;
this.callbacks = [];
this.id = impl.newFilter(options);
web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));
options = getOptions(options);
var callbacks = [];
var filterId = implementation.newFilter(options);
var onMessages = function (messages) {
messages.forEach(function (message) {
message = formatter ? formatter(message) : message;
callbacks.forEach(function (callback) {
callback(message);
});
});
};
/// alias for changed*
Filter.prototype.arrived = function(callback) {
this.changed(callback);
};
Filter.prototype.happened = function(callback) {
this.changed(callback);
implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);
var changed = function (callback) {
callbacks.push(callback);
};
/// gets called when there is new eth/shh message
Filter.prototype.changed = function(callback) {
this.callbacks.push(callback);
var messages = function () {
return implementation.getMessages(filterId);
};
/// trigger calling new message from people
Filter.prototype.trigger = function(messages) {
for (var i = 0; i < this.callbacks.length; i++) {
for (var j = 0; j < messages.length; j++) {
var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j];
this.callbacks[i].call(this, message);
}
}
var uninstall = function () {
implementation.stopPolling(filterId);
implementation.uninstallFilter(filterId);
callbacks = [];
};
/// should be called to uninstall current filter
Filter.prototype.uninstall = function() {
this.impl.uninstallFilter(this.id);
web3.provider.stopPolling(this.id);
return {
changed: changed,
arrived: changed,
happened: changed,
messages: messages,
logs: messages,
uninstall: uninstall
};
};
/// should be called to manually trigger getting latest messages from the client
Filter.prototype.messages = function() {
return this.impl.getMessages(this.id);
};
module.exports = filter;
/// alias for messages
Filter.prototype.logs = function () {
return this.messages();
};
module.exports = Filter;
},{"./web3":13}],6:[function(require,module,exports){
},{}],8:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -770,6 +909,7 @@ var padLeft = function (string, chars, sign) {
/// If the value is floating point, round it down
/// @returns right-aligned byte representation of int
var formatInputInt = function (value) {
/*jshint maxcomplexity:7 */
var padding = c.ETH_PADDING * 2;
if (value instanceof BigNumber || typeof value === 'number') {
if (typeof value === 'number')
@ -883,7 +1023,7 @@ module.exports = {
};
},{"./const":2,"./utils":12}],7:[function(require,module,exports){
},{"./const":2,"./utils":15}],9:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -923,15 +1063,17 @@ HttpSyncProvider.prototype.send = function (payload) {
request.open('POST', this.host, false);
request.send(JSON.stringify(payload));
// check request.status
var result = request.responseText;
// check request.status
if(request.status !== 200)
return;
return JSON.parse(result);
};
module.exports = HttpSyncProvider;
},{}],8:[function(require,module,exports){
},{}],10:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -998,111 +1140,7 @@ module.exports = {
},{}],9:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js 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.
ethereum.js 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 ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file providermanager.js
* @authors:
* Jeffrey Wilcke <jeff@ethdev.com>
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* Gav Wood <g@ethdev.com>
* @date 2014
*/
var web3 = require('./web3');
var jsonrpc = require('./jsonrpc');
/**
* Provider manager object prototype
* It's responsible for passing messages to providers
* If no provider is set it's responsible for queuing requests
* It's also responsible for polling the ethereum node for incoming messages
* Default poll timeout is 12 seconds
* If we are running ethereum.js inside ethereum browser, there are backend based tools responsible for polling,
* and provider manager polling mechanism is not used
*/
var ProviderManager = function() {
this.polls = [];
this.provider = undefined;
var self = this;
var poll = function () {
self.polls.forEach(function (data) {
var result = self.send(data.data);
if (!(result instanceof Array) || result.length === 0) {
return;
}
data.callback(result);
});
setTimeout(poll, 1000);
};
poll();
};
/// sends outgoing requests
/// @params data - an object with at least 'method' property
ProviderManager.prototype.send = function(data) {
var payload = jsonrpc.toPayload(data.method, data.params);
if (this.provider === undefined) {
console.error('provider is not set');
return null;
}
var result = this.provider.send(payload);
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return null;
}
return result.result;
};
/// setups provider, which will be used for sending messages
ProviderManager.prototype.set = function(provider) {
this.provider = provider;
};
/// this method is only used, when we do not have native qt bindings and have to do polling on our own
/// should be callled, on start watching for eth/shh changes
ProviderManager.prototype.startPolling = function (data, pollId, callback) {
this.polls.push({data: data, id: pollId, callback: callback});
};
/// should be called to stop polling for certain watch changes
ProviderManager.prototype.stopPolling = function (pollId) {
for (var i = this.polls.length; i--;) {
var poll = this.polls[i];
if (poll.id === pollId) {
this.polls.splice(i, 1);
}
}
};
module.exports = ProviderManager;
},{"./jsonrpc":8,"./web3":13}],10:[function(require,module,exports){
},{}],11:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1137,7 +1175,160 @@ QtSyncProvider.prototype.send = function (payload) {
module.exports = QtSyncProvider;
},{}],11:[function(require,module,exports){
},{}],12:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js 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.
ethereum.js 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 ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file requestmanager.js
* @authors:
* Jeffrey Wilcke <jeff@ethdev.com>
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* Gav Wood <g@ethdev.com>
* @date 2014
*/
var jsonrpc = require('./jsonrpc');
var c = require('./const');
/**
* It's responsible for passing messages to providers
* It's also responsible for polling the ethereum node for incoming messages
* Default poll timeout is 1 second
*/
var requestManager = function() {
var polls = [];
var timeout = null;
var provider;
var send = function (data) {
var payload = jsonrpc.toPayload(data.method, data.params);
if (!provider) {
console.error('provider is not set');
return null;
}
var result = provider.send(payload);
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return null;
}
return result.result;
};
var setProvider = function (p) {
provider = p;
};
/*jshint maxparams:4 */
var startPolling = function (data, pollId, callback, uninstall) {
polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});
};
/*jshint maxparams:3 */
var stopPolling = function (pollId) {
for (var i = polls.length; i--;) {
var poll = polls[i];
if (poll.id === pollId) {
polls.splice(i, 1);
}
}
};
var reset = function () {
polls.forEach(function (poll) {
poll.uninstall(poll.id);
});
polls = [];
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
poll();
};
var poll = function () {
polls.forEach(function (data) {
var result = send(data.data);
if (!(result instanceof Array) || result.length === 0) {
return;
}
data.callback(result);
});
timeout = setTimeout(poll, c.ETH_POLLING_TIMEOUT);
};
poll();
return {
send: send,
setProvider: setProvider,
startPolling: startPolling,
stopPolling: stopPolling,
reset: reset
};
};
module.exports = requestManager;
},{"./const":2,"./jsonrpc":10}],13:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js 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.
ethereum.js 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 ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file shh.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
/// @returns an array of objects describing web3.shh api methods
var methods = function () {
return [
{ name: 'post', call: 'shh_post' },
{ name: 'newIdentity', call: 'shh_newIdentity' },
{ name: 'haveIdentity', call: 'shh_haveIdentity' },
{ name: 'newGroup', call: 'shh_newGroup' },
{ name: 'addToGroup', call: 'shh_addToGroup' }
];
};
module.exports = {
methods: methods
};
},{}],14:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1218,7 +1409,7 @@ module.exports = {
};
},{"./formatters":6}],12:[function(require,module,exports){
},{"./formatters":8}],15:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1328,6 +1519,7 @@ var filterEvents = function (json) {
/// TODO: use BigNumber.js to parse int
/// TODO: add tests for it!
var toEth = function (str) {
/*jshint maxcomplexity:7 */
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0;
var units = c.ETH_UNITS;
@ -1362,7 +1554,58 @@ module.exports = {
};
},{"./const":2}],13:[function(require,module,exports){
},{"./const":2}],16:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js 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.
ethereum.js 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 ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file watches.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
/// @returns an array of objects describing web3.eth.watch api methods
var eth = function () {
var newFilter = function (args) {
return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';
};
return [
{ name: 'newFilter', call: newFilter },
{ name: 'uninstallFilter', call: 'eth_uninstallFilter' },
{ name: 'getMessages', call: 'eth_filterLogs' }
];
};
/// @returns an array of objects describing web3.shh.watch api methods
var shh = function () {
return [
{ name: 'newFilter', call: 'shh_newFilter' },
{ name: 'uninstallFilter', call: 'shh_uninstallFilter' },
{ name: 'getMessages', call: 'shh_getMessages' }
];
};
module.exports = {
eth: eth,
shh: shh
};
},{}],17:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1392,7 +1635,13 @@ if ("build" !== 'build') {/*
var BigNumber = require('bignumber.js');
*/}
var eth = require('./eth');
var db = require('./db');
var shh = require('./shh');
var watches = require('./watches');
var filter = require('./filter');
var utils = require('./utils');
var requestManager = require('./requestmanager');
/// @returns an array of objects describing web3 api methods
var web3Methods = function () {
@ -1401,100 +1650,6 @@ var web3Methods = function () {
];
};
/// @returns an array of objects describing web3.eth api methods
var ethMethods = function () {
var blockCall = function (args) {
return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
};
var transactionCall = function (args) {
return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber';
};
var uncleCall = function (args) {
return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber';
};
var methods = [
{ name: 'balanceAt', call: 'eth_balanceAt' },
{ name: 'register', call: 'eth_register' },
{ name: 'unregister', call: 'eth_unregister' },
{ name: 'stateAt', call: 'eth_stateAt' },
{ name: 'storageAt', call: 'eth_storageAt' },
{ name: 'countAt', call: 'eth_countAt'},
{ name: 'codeAt', call: 'eth_codeAt' },
{ name: 'transact', call: 'eth_transact' },
{ name: 'call', call: 'eth_call' },
{ name: 'block', call: blockCall },
{ name: 'transaction', call: transactionCall },
{ name: 'uncle', call: uncleCall },
{ name: 'compilers', call: 'eth_compilers' },
{ name: 'flush', call: 'eth_flush' },
{ name: 'lll', call: 'eth_lll' },
{ name: 'solidity', call: 'eth_solidity' },
{ name: 'serpent', call: 'eth_serpent' },
{ name: 'logs', call: 'eth_logs' }
];
return methods;
};
/// @returns an array of objects describing web3.eth api properties
var ethProperties = function () {
return [
{ name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },
{ name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },
{ name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },
{ name: 'gasPrice', getter: 'eth_gasPrice' },
{ name: 'accounts', getter: 'eth_accounts' },
{ name: 'peerCount', getter: 'eth_peerCount' },
{ name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },
{ name: 'number', getter: 'eth_number'}
];
};
/// @returns an array of objects describing web3.db api methods
var dbMethods = function () {
return [
{ name: 'put', call: 'db_put' },
{ name: 'get', call: 'db_get' },
{ name: 'putString', call: 'db_putString' },
{ name: 'getString', call: 'db_getString' }
];
};
/// @returns an array of objects describing web3.shh api methods
var shhMethods = function () {
return [
{ name: 'post', call: 'shh_post' },
{ name: 'newIdentity', call: 'shh_newIdentity' },
{ name: 'haveIdentity', call: 'shh_haveIdentity' },
{ name: 'newGroup', call: 'shh_newGroup' },
{ name: 'addToGroup', call: 'shh_addToGroup' }
];
};
/// @returns an array of objects describing web3.eth.watch api methods
var ethWatchMethods = function () {
var newFilter = function (args) {
return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';
};
return [
{ name: 'newFilter', call: newFilter },
{ name: 'uninstallFilter', call: 'eth_uninstallFilter' },
{ name: 'getMessages', call: 'eth_filterLogs' }
];
};
/// @returns an array of objects describing web3.shh.watch api methods
var shhWatchMethods = function () {
return [
{ name: 'newFilter', call: 'shh_newFilter' },
{ name: 'uninstallFilter', call: 'shh_uninstallFilter' },
{ name: 'getMessages', call: 'shh_getMessages' }
];
};
/// creates methods in a given object based on method description on input
/// setups api calls for these methods
var setupMethods = function (obj, methods) {
@ -1502,7 +1657,7 @@ var setupMethods = function (obj, methods) {
obj[method.name] = function () {
var args = Array.prototype.slice.call(arguments);
var call = typeof method.call === 'function' ? method.call(args) : method.call;
return web3.provider.send({
return web3.manager.send({
method: call,
params: args
});
@ -1516,14 +1671,14 @@ var setupProperties = function (obj, properties) {
properties.forEach(function (property) {
var proto = {};
proto.get = function () {
return web3.provider.send({
return web3.manager.send({
method: property.getter
});
};
if (property.setter) {
proto.set = function (val) {
return web3.provider.send({
return web3.manager.send({
method: property.setter,
params: [val]
});
@ -1533,10 +1688,32 @@ var setupProperties = function (obj, properties) {
});
};
/*jshint maxparams:4 */
var startPolling = function (method, id, callback, uninstall) {
web3.manager.startPolling({
method: method,
params: [id]
}, id, callback, uninstall);
};
/*jshint maxparams:3 */
var stopPolling = function (id) {
web3.manager.stopPolling(id);
};
var ethWatch = {
startPolling: startPolling.bind(null, 'eth_changed'),
stopPolling: stopPolling
};
var shhWatch = {
startPolling: startPolling.bind(null, 'shh_changed'),
stopPolling: stopPolling
};
/// setups web3 object, and it's in-browser executed methods
var web3 = {
_callbacks: {},
_events: {},
manager: requestManager(),
providers: {},
/// @returns ascii string representation of hex value prefixed with 0x
@ -1575,12 +1752,15 @@ var web3 = {
/// @param filter may be a string, object or event
/// @param indexed is optional, this is an object with optional event indexed params
/// @param options is optional, this is an object with optional event options ('max'...)
watch: function (filter, indexed, options) {
if (filter._isEvent) {
return filter(indexed, options);
/// TODO: fix it, 4 params? no way
/*jshint maxparams:4 */
watch: function (fil, indexed, options, formatter) {
if (fil._isEvent) {
return fil(indexed, options);
}
return new web3.filter(filter, ethWatch);
return filter(fil, ethWatch, formatter);
}
/*jshint maxparams:3 */
},
/// db object prototype
@ -1588,54 +1768,44 @@ var web3 = {
/// shh object prototype
shh: {
/// @param filter may be a string, object or event
watch: function (filter, indexed) {
return new web3.filter(filter, shhWatch);
watch: function (fil) {
return filter(fil, shhWatch);
}
},
setProvider: function (provider) {
web3.manager.setProvider(provider);
},
/// Should be called to reset state of web3 object
/// Resets everything except manager
reset: function () {
web3.manager.reset();
}
};
/// setups all api methods
setupMethods(web3, web3Methods());
setupMethods(web3.eth, ethMethods());
setupProperties(web3.eth, ethProperties());
setupMethods(web3.db, dbMethods());
setupMethods(web3.shh, shhMethods());
var ethWatch = {
changed: 'eth_changed'
};
setupMethods(ethWatch, ethWatchMethods());
var shhWatch = {
changed: 'shh_changed'
};
setupMethods(shhWatch, shhWatchMethods());
web3.setProvider = function(provider) {
web3.provider.set(provider);
};
setupMethods(web3.eth, eth.methods());
setupProperties(web3.eth, eth.properties());
setupMethods(web3.db, db.methods());
setupMethods(web3.shh, shh.methods());
setupMethods(ethWatch, watches.eth());
setupMethods(shhWatch, watches.shh());
module.exports = web3;
},{"./utils":12}],"web3":[function(require,module,exports){
},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3');
var ProviderManager = require('./lib/providermanager');
web3.provider = new ProviderManager();
web3.filter = require('./lib/filter');
web3.providers.HttpSyncProvider = require('./lib/httpsync');
web3.providers.QtSyncProvider = require('./lib/qtsync');
web3.eth.contract = require('./lib/contract');
web3.abi = require('./lib/abi');
module.exports = web3;
},{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"])
},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"])
//# sourceMappingURL=ethereum.js.map

View File

@ -981,7 +981,7 @@ ApplicationWindow {
anchors.top: parent.top
anchors.topMargin: 30
font.pointSize: 12
text: "<h2>Mist (0.8.5)</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Viktor Trón<br>Felix Lange<br>Taylor Gerring<br>Daniel Nagy<br>Gustav Simonsson<br><h3>UX/UI</h3>Alex van de Sande<br>Fabian Vogelsteller"
text: "<h2>Mist (0.8.6)</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Viktor Trón<br>Felix Lange<br>Taylor Gerring<br>Daniel Nagy<br>Gustav Simonsson<br><h3>UX/UI</h3>Alex van de Sande<br>Fabian Vogelsteller"
}
}

View File

@ -24,7 +24,6 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/ui/qt"
"github.com/ethereum/go-ethereum/xeth"
"github.com/obscuren/qml"
)
@ -116,7 +115,3 @@ func (app *ExtApplication) mainLoop() {
}
}
}
func (self *ExtApplication) Watch(filterOptions map[string]interface{}, identifier string) {
self.filters[identifier] = qt.NewFilterFromMap(filterOptions, self.eth)
}

View File

@ -26,13 +26,11 @@ import (
"fmt"
"log"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
"bitbucket.org/kardianos/osext"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/vm"
@ -43,9 +41,8 @@ var (
KeyRing string
KeyStore string
StartRpc bool
StartWebSockets bool
RpcListenAddress string
RpcPort int
WsPort int
OutboundPort string
ShowGenesis bool
AddPeer string
@ -68,38 +65,7 @@ var (
// flags specific to gui client
var AssetPath string
//TODO: If we re-use the one defined in cmd.go the binary osx image crashes. If somebody finds out why we can dry this up.
func defaultAssetPath() string {
var assetPath string
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/mist"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
return assetPath
}
func defaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereum")
}
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini")
func Init() {
// TODO: move common flag processing to cmd/utils
@ -111,22 +77,21 @@ func Init() {
flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug")
flag.StringVar(&Identifier, "id", "", "Custom client identifier")
flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)")
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file")
flag.StringVar(&RpcListenAddress, "rpcaddr", "127.0.0.1", "address for json-rpc server to listen on")
flag.IntVar(&RpcPort, "rpcport", 8545, "port to start json-rpc server on")
flag.IntVar(&WsPort, "wsport", 40404, "port to start websocket rpc server on")
flag.BoolVar(&StartRpc, "rpc", true, "start rpc server")
flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)")
flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use")
flag.StringVar(&Datadir, "datadir", ethutil.DefaultDataDir(), "specifies the datadir to use")
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5 (= silent,error,warn,info,debug,debug detail)")
flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory")
flag.StringVar(&AssetPath, "asset_path", ethutil.DefaultAssetPath(), "absolute path to GUI assets directory")
// Network stuff
var (

View File

@ -36,7 +36,7 @@ import (
const (
ClientIdentifier = "Mist"
Version = "0.8.5"
Version = "0.8.6"
)
var ethereum *eth.Ethereum
@ -73,11 +73,7 @@ func run() error {
utils.KeyTasks(ethereum.KeyManager(), KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
if StartRpc {
utils.StartRpc(ethereum, RpcPort)
}
if StartWebSockets {
utils.StartWebSockets(ethereum, WsPort)
utils.StartRpc(ethereum, RpcListenAddress, RpcPort)
}
gui := NewWindow(ethereum, config, KeyRing, LogLevel)

View File

@ -25,12 +25,8 @@ import (
"fmt"
"os"
"os/signal"
"path"
"path/filepath"
"regexp"
"runtime"
"bitbucket.org/kardianos/osext"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
@ -39,7 +35,6 @@ import (
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/rlp"
rpchttp "github.com/ethereum/go-ethereum/rpc/http"
rpcws "github.com/ethereum/go-ethereum/rpc/ws"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/xeth"
)
@ -132,31 +127,6 @@ func StartEthereum(ethereum *eth.Ethereum) {
})
}
func DefaultAssetPath() string {
var assetPath string
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/mist"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
return assetPath
}
func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
var err error
@ -189,9 +159,9 @@ func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, Secre
clilogger.Infof("Main address %x\n", keyManager.Address())
}
func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
func StartRpc(ethereum *eth.Ethereum, RpcListenAddress string, RpcPort int) {
var err error
ethereum.RpcServer, err = rpchttp.NewRpcHttpServer(xeth.New(ethereum), RpcPort)
ethereum.RpcServer, err = rpchttp.NewRpcHttpServer(xeth.New(ethereum), RpcListenAddress, RpcPort)
if err != nil {
clilogger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
} else {
@ -199,18 +169,6 @@ func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
}
}
func StartWebSockets(eth *eth.Ethereum, wsPort int) {
clilogger.Infoln("Starting WebSockets")
var err error
eth.WsServer, err = rpcws.NewWebSocketServer(xeth.New(eth), wsPort)
if err != nil {
clilogger.Errorf("Could not start RPC interface (port %v): %v", wsPort, err)
} else {
go eth.WsServer.Start()
}
}
var gminer *miner.Miner
func GetMiner() *miner.Miner {

View File

@ -50,7 +50,6 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
sm := &BlockProcessor{
db: db,
mem: make(map[string]*big.Int),
//Pow: &ethash.Ethash{},
Pow: ezp.New(),
bc: chainManager,
eventMux: eventMux,
@ -62,7 +61,7 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
coinbase.SetGasPool(CalcGasLimit(parent, block))
coinbase.SetGasPool(block.Header().GasLimit)
// Process the transactions on to parent state
receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
@ -100,7 +99,8 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
// Notify all subscribers
if !transientProcess {
go self.eventMux.Post(TxPostEvent{tx})
go self.eventMux.Post(statedb.Logs())
logs := statedb.Logs()
go self.eventMux.Post(logs)
}
return receipt, txGas, err
@ -247,6 +247,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
}
expl := CalcGasLimit(parent, block)
if expl.Cmp(block.Header().GasLimit) != 0 {
return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl)
}
if block.Time() < parent.Time() {
return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time)
}

View File

@ -85,12 +85,14 @@ type ChainManager struct {
lastBlockHash []byte
transState *state.StateDB
txState *state.StateDB
}
func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
bc.setLastBlock()
bc.transState = bc.State().Copy()
bc.txState = bc.State().Copy()
return bc
}
@ -138,6 +140,19 @@ func (self *ChainManager) TransState() *state.StateDB {
return self.transState
}
func (self *ChainManager) TxState() *state.StateDB {
self.tsmu.RLock()
defer self.tsmu.RUnlock()
return self.txState
}
func (self *ChainManager) setTxState(state *state.StateDB) {
self.tsmu.Lock()
defer self.tsmu.Unlock()
self.txState = state
}
func (self *ChainManager) setTransState(statedb *state.StateDB) {
self.transState = statedb
}
@ -268,7 +283,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
break
}
}
fmt.Printf("get hash %x (%d)\n", hash, len(chain))
return
}
@ -363,6 +377,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
defer self.tsmu.Unlock()
for _, block := range chain {
// Call in to the block processor and check for errors. It's likely that if one block fails
// all others will fail too (unless a known block is returned).
td, err := self.processor.Process(block)
if err != nil {
if IsKnownBlockErr(err) {
@ -377,11 +393,15 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
}
block.Td = td
var chain, split bool
var canonical, split bool
self.mu.Lock()
{
// Write block to database. Eventually we'll have to improve on this and throw away blocks that are
// not in the canonical chain.
self.write(block)
cblock := self.currentBlock
// Compare the TD of the last known block in the canonical chain to make sure it's greater.
// At this point it's possible that a different chain (fork) becomes the new canonical chain.
if td.Cmp(self.td) > 0 {
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
@ -391,17 +411,18 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
self.setTotalDifficulty(td)
self.insert(block)
chain = true
canonical = true
}
}
self.mu.Unlock()
if chain {
if canonical {
self.setTransState(state.New(block.Root(), self.db))
self.eventMux.Post(ChainEvent{block, td})
}
if split {
self.setTransState(state.New(block.Root(), self.db))
self.setTxState(state.New(block.Root(), self.db))
self.eventMux.Post(ChainSplitEvent{block})
}
}

View File

@ -17,7 +17,7 @@ type FilterOptions struct {
Latest int64
Address [][]byte
Topics [][]byte
Topics [][][]byte
Skip int
Max int
@ -31,7 +31,7 @@ type Filter struct {
skip int
address [][]byte
max int
topics [][]byte
topics [][][]byte
BlockCallback func(*types.Block)
PendingCallback func(*types.Block)
@ -44,6 +44,8 @@ func NewFilter(eth Backend) *Filter {
return &Filter{eth: eth}
}
// SetOptions copies the filter options to the filter it self. The reason for this "silly" copy
// is simply because named arguments in this case is extremely nice and readable.
func (self *Filter) SetOptions(options FilterOptions) {
self.earliest = options.Earliest
self.latest = options.Latest
@ -69,7 +71,7 @@ func (self *Filter) SetAddress(addr [][]byte) {
self.address = addr
}
func (self *Filter) SetTopics(topics [][]byte) {
func (self *Filter) SetTopics(topics [][][]byte) {
self.topics = topics
}
@ -149,12 +151,20 @@ Logs:
continue
}
max := int(math.Min(float64(len(self.topics)), float64(len(log.Topics()))))
for i := 0; i < max; i++ {
if !bytes.Equal(log.Topics()[i], self.topics[i]) {
logTopics := make([][]byte, len(self.topics))
copy(logTopics, log.Topics())
for i, topics := range self.topics {
for _, topic := range topics {
var match bool
if bytes.Equal(log.Topics()[i], topic) {
match = true
}
if !match {
continue Logs
}
}
}
ret = append(ret, log)
}
@ -177,8 +187,15 @@ func (self *Filter) bloomFilter(block *types.Block) bool {
}
}
for _, topic := range self.topics {
if !types.BloomLookup(block.Bloom(), topic) {
for _, sub := range self.topics {
var included bool
for _, topic := range sub {
if types.BloomLookup(block.Bloom(), topic) {
included = true
break
}
}
if !included {
return false
}
}

View File

@ -51,8 +51,6 @@ func GenesisBlock(db ethutil.Database) *types.Block {
statedb.Sync()
genesis.Header().Root = statedb.Root()
fmt.Printf("+++ genesis +++\nRoot: %x\nHash: %x\n", genesis.Header().Root, genesis.Hash())
return genesis
}

View File

@ -126,7 +126,7 @@ func (self *StateTransition) BuyGas() error {
self.AddGas(self.msg.Gas())
self.initialGas.Set(self.msg.Gas())
sender.SubAmount(MessageGasValue(self.msg))
sender.SubBalance(MessageGasValue(self.msg))
return nil
}
@ -251,7 +251,7 @@ func (self *StateTransition) RefundGas() {
coinbase, sender := self.Coinbase(), self.From()
// Return remaining gas
remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice())
sender.AddAmount(remaining)
sender.AddBalance(remaining)
uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2)
for addr, ref := range self.state.Refunds() {

View File

@ -30,7 +30,6 @@ import (
"io"
"io/ioutil"
"os"
"os/user"
"path"
)
@ -48,12 +47,6 @@ type keyStorePlain struct {
keysDirPath string
}
// TODO: copied from cmd/ethereum/flags.go
func DefaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereum")
}
func NewKeyStorePlain(path string) KeyStore2 {
return &keyStorePlain{path}
}
@ -126,8 +119,11 @@ func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
}
addresses = make([][]byte, len(fileInfos))
for i, fileInfo := range fileInfos {
addresses[i] = make([]byte, 40)
addresses[i] = []byte(fileInfo.Name())
address, err := hex.DecodeString(fileInfo.Name())
if err != nil {
continue
}
addresses[i] = address
}
return addresses, err
}

View File

@ -2,12 +2,13 @@ package crypto
import (
"github.com/ethereum/go-ethereum/crypto/randentropy"
"github.com/ethereum/go-ethereum/ethutil"
"reflect"
"testing"
)
func TestKeyStorePlain(t *testing.T) {
ks := NewKeyStorePlain(DefaultDataDir())
ks := NewKeyStorePlain(ethutil.DefaultDataDir())
pass := "" // not used but required by API
k1, err := ks.GenerateNewKey(randentropy.Reader, pass)
if err != nil {
@ -35,7 +36,7 @@ func TestKeyStorePlain(t *testing.T) {
}
func TestKeyStorePassphrase(t *testing.T) {
ks := NewKeyStorePassphrase(DefaultDataDir())
ks := NewKeyStorePassphrase(ethutil.DefaultDataDir())
pass := "foo"
k1, err := ks.GenerateNewKey(randentropy.Reader, pass)
if err != nil {
@ -61,7 +62,7 @@ func TestKeyStorePassphrase(t *testing.T) {
}
func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
ks := NewKeyStorePassphrase(DefaultDataDir())
ks := NewKeyStorePassphrase(ethutil.DefaultDataDir())
pass := "foo"
k1, err := ks.GenerateNewKey(randentropy.Reader, pass)
if err != nil {
@ -89,7 +90,7 @@ func TestImportPreSaleKey(t *testing.T) {
// python pyethsaletool.py genwallet
// with password "foo"
fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
ks := NewKeyStorePassphrase(DefaultDataDir())
ks := NewKeyStorePassphrase(ethutil.DefaultDataDir())
pass := "foo"
_, err := ImportPreSaleKey(ks, []byte(fileContent), pass)
if err != nil {

View File

@ -12,7 +12,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
ethlogger "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
@ -23,8 +23,8 @@ import (
)
var (
logger = ethlogger.NewLogger("SERV")
jsonlogger = ethlogger.NewJsonLogger()
ethlogger = logger.NewLogger("SERV")
jsonlogger = logger.NewJsonLogger()
defaultBootNodes = []*discover.Node{
// ETH/DEV cmd/bootnode
@ -74,7 +74,7 @@ func (cfg *Config) parseBootNodes() []*discover.Node {
}
n, err := discover.ParseNode(url)
if err != nil {
logger.Errorf("Bootstrap URL %s: %v\n", url, err)
ethlogger.Errorf("Bootstrap URL %s: %v\n", url, err)
continue
}
ns = append(ns, n)
@ -98,7 +98,7 @@ func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
return nil, fmt.Errorf("could not generate server key: %v", err)
}
if err := ioutil.WriteFile(keyfile, crypto.FromECDSA(key), 0600); err != nil {
logger.Errorln("could not persist nodekey: ", err)
ethlogger.Errorln("could not persist nodekey: ", err)
}
return key, nil
}
@ -127,17 +127,16 @@ type Ethereum struct {
miner *miner.Miner
RpcServer rpc.RpcServer
WsServer rpc.RpcServer
keyManager *crypto.KeyManager
logger ethlogger.LogSystem
logger logger.LogSystem
Mining bool
}
func New(config *Config) (*Ethereum, error) {
// Boostrap database
logger := ethlogger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
ethlogger := logger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
db, err := ethdb.NewLDBDatabase("blockchain")
if err != nil {
return nil, err
@ -147,7 +146,8 @@ func New(config *Config) (*Ethereum, error) {
d, _ := db.Get([]byte("ProtocolVersion"))
protov := ethutil.NewValue(d).Uint()
if protov != ProtocolVersion && protov != 0 {
return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, ethutil.Config.ExecPath+"/database")
path := path.Join(config.DataDir, "blockchain")
return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, path)
}
// Create new keymanager
@ -173,7 +173,7 @@ func New(config *Config) (*Ethereum, error) {
keyManager: keyManager,
blacklist: p2p.NewBlacklist(),
eventMux: &event.TypeMux{},
logger: logger,
logger: ethlogger,
}
eth.chainManager = core.NewChainManager(db, eth.EventMux())
@ -215,7 +215,7 @@ func New(config *Config) (*Ethereum, error) {
}
func (s *Ethereum) KeyManager() *crypto.KeyManager { return s.keyManager }
func (s *Ethereum) Logger() ethlogger.LogSystem { return s.logger }
func (s *Ethereum) Logger() logger.LogSystem { return s.logger }
func (s *Ethereum) Name() string { return s.net.Name }
func (s *Ethereum) ChainManager() *core.ChainManager { return s.chainManager }
func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcessor }
@ -233,7 +233,7 @@ func (s *Ethereum) Coinbase() []byte { return nil } // TODO
// Start the ethereum
func (s *Ethereum) Start() error {
jsonlogger.LogJson(&ethlogger.LogStarting{
jsonlogger.LogJson(&logger.LogStarting{
ClientString: s.net.Name,
ProtocolVersion: ProtocolVersion,
})
@ -259,7 +259,7 @@ func (s *Ethereum) Start() error {
s.blockSub = s.eventMux.Subscribe(core.NewMinedBlockEvent{})
go s.blockBroadcastLoop()
logger.Infoln("Server started")
ethlogger.Infoln("Server started")
return nil
}
@ -284,9 +284,7 @@ func (s *Ethereum) Stop() {
if s.RpcServer != nil {
s.RpcServer.Stop()
}
if s.WsServer != nil {
s.WsServer.Stop()
}
s.txPool.Stop()
s.eventMux.Stop()
s.blockPool.Stop()
@ -294,7 +292,7 @@ func (s *Ethereum) Stop() {
s.whisper.Stop()
}
logger.Infoln("Server stopped")
ethlogger.Infoln("Server stopped")
close(s.shutdownChan)
}

View File

@ -12,11 +12,11 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
ethlogger "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
)
var poolLogger = ethlogger.NewLogger("Blockpool")
var poolLogger = logger.NewLogger("Blockpool")
const (
blockHashesBatchSize = 256

View File

@ -12,19 +12,19 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
ethlogger "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
)
const waitTimeout = 60 // seconds
var logsys = ethlogger.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlogger.LogLevel(ethlogger.DebugDetailLevel))
var logsys = logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(logger.DebugDetailLevel))
var ini = false
func logInit() {
if !ini {
ethlogger.AddLogSystem(logsys)
logger.AddLogSystem(logsys)
ini = true
}
}

View File

@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
)
@ -137,6 +138,12 @@ func (self *ethProtocol) handle() error {
if err := msg.Decode(&txs); err != nil {
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
}
for _, tx := range txs {
jsonlogger.LogJson(&logger.EthTxReceived{
TxHash: ethutil.Bytes2Hex(tx.Hash()),
RemoteId: self.peer.ID().String(),
})
}
self.txPool.AddTransactions(txs)
case GetBlockHashesMsg:

View File

@ -12,12 +12,12 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
ethlogger "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
)
var sys = ethlogger.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlogger.LogLevel(ethlogger.DebugDetailLevel))
var sys = logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(logger.DebugDetailLevel))
type testMsgReadWriter struct {
in chan p2p.Msg

View File

@ -3,10 +3,60 @@ package ethutil
import (
"fmt"
"math/big"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
"time"
"github.com/kardianos/osext"
)
func DefaultAssetPath() string {
var assetPath string
pwd, _ := os.Getwd()
srcdir := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist")
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
if pwd == srcdir {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/mist"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
// Check if the assetPath exists. If not, try the source directory
// This happens when binary is run from outside cmd/mist directory
if _, err := os.Stat(assetPath); os.IsNotExist(err) {
assetPath = path.Join(srcdir, "assets")
}
return assetPath
}
func DefaultDataDir() string {
usr, _ := user.Current()
if runtime.GOOS == "darwin" {
return path.Join(usr.HomeDir, "Library/Ethereum")
} else if runtime.GOOS == "windows" {
return path.Join(usr.HomeDir, "AppData/Roaming/Ethereum")
} else {
return path.Join(usr.HomeDir, ".ethereum")
}
}
func IsWindows() bool {
return runtime.GOOS == "windows"
}

View File

@ -3,7 +3,6 @@ package filter
// TODO make use of the generic filtering system
import (
"fmt"
"sync"
"github.com/ethereum/go-ethereum/core"
@ -75,7 +74,6 @@ out:
case event := <-events.Chan():
switch event := event.(type) {
case core.ChainEvent:
fmt.Println("filter start")
self.filterMu.RLock()
for _, filter := range self.filters {
if filter.BlockCallback != nil {
@ -83,7 +81,6 @@ out:
}
}
self.filterMu.RUnlock()
fmt.Println("filter stop")
case core.PendingBlockEvent:
self.filterMu.RLock()

View File

@ -1,53 +0,0 @@
#!/bin/sh
if [ "$1" == "" ]; then
echo "Usage $0 executable branch"
echo "executable ethereum | mist"
echo "branch develop | master"
exit
fi
exe=$1
path=$exe
branch=$2
if [ "$branch" == "develop" ]; then
path="cmd/$exe"
fi
# Test if go is installed
command -v go >/dev/null 2>&1 || { echo >&2 "Unable to find 'go'. This script requires go."; exit 1; }
# Test if $GOPATH is set
if [ "$GOPATH" == "" ]; then
echo "\$GOPATH not set"
exit
fi
echo "changing branch to $branch"
cd $GOPATH/src/github.com/ethereum/go-ethereum
git checkout $branch
# installing package dependencies doesn't work for develop
# branch as go get always pulls from master head
# so build will continue to fail, but this installs locally
# for people who git clone since go install will manage deps
#echo "go get -u -d github.com/ethereum/go-ethereum/$path"
#go get -v -u -d github.com/ethereum/go-ethereum/$path
#if [ $? != 0 ]; then
# echo "go get failed"
# exit
#fi
cd $GOPATH/src/github.com/ethereum/go-ethereum/$path
if [ "$exe" == "mist" ]; then
echo "Building Mist GUI. Assuming Qt is installed. If this step"
echo "fails; please refer to: https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)"
else
echo "Building ethereum CLI."
fi
go install
echo "done. Please run $exe :-)"

View File

@ -24,7 +24,7 @@ var jsrelogger = logger.NewLogger("JSRE")
type JSRE struct {
ethereum *eth.Ethereum
Vm *otto.Otto
pipe *xeth.XEth
xeth *xeth.XEth
events event.Subscription
@ -67,7 +67,7 @@ func NewJSRE(ethereum *eth.Ethereum) *JSRE {
// We have to make sure that, whoever calls this, calls "Stop"
go re.mainLoop()
re.Bind("eth", &JSEthereum{re.pipe, re.Vm, ethereum})
re.Bind("eth", &JSEthereum{re.xeth, re.Vm, ethereum})
re.initStdFuncs()
@ -113,12 +113,10 @@ func (self *JSRE) mainLoop() {
func (self *JSRE) initStdFuncs() {
t, _ := self.Vm.Get("eth")
eth := t.Object()
eth.Set("watch", self.watch)
eth.Set("addPeer", self.addPeer)
eth.Set("connect", self.connect)
eth.Set("require", self.require)
eth.Set("stopMining", self.stopMining)
eth.Set("startMining", self.startMining)
eth.Set("execBlock", self.execBlock)
eth.Set("dump", self.dump)
eth.Set("export", self.export)
}
@ -152,7 +150,8 @@ func (self *JSRE) dump(call otto.FunctionCall) otto.Value {
}
statedb := state.New(block.Root(), self.ethereum.Db())
v, _ := self.Vm.ToValue(statedb.Dump())
v, _ := self.Vm.ToValue(statedb.RawDump())
return v
}
@ -167,36 +166,7 @@ func (self *JSRE) startMining(call otto.FunctionCall) otto.Value {
return v
}
// eth.watch
func (self *JSRE) watch(call otto.FunctionCall) otto.Value {
addr, _ := call.Argument(0).ToString()
var storageAddr string
var cb otto.Value
var storageCallback bool
if len(call.ArgumentList) > 2 {
storageCallback = true
storageAddr, _ = call.Argument(1).ToString()
cb = call.Argument(2)
} else {
cb = call.Argument(1)
}
if storageCallback {
self.objectCb[addr+storageAddr] = append(self.objectCb[addr+storageAddr], cb)
// event := "storage:" + string(ethutil.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr))
// self.ethereum.EventMux().Subscribe(event, self.changeChan)
} else {
self.objectCb[addr] = append(self.objectCb[addr], cb)
// event := "object:" + string(ethutil.Hex2Bytes(addr))
// self.ethereum.EventMux().Subscribe(event, self.changeChan)
}
return otto.UndefinedValue()
}
func (self *JSRE) addPeer(call otto.FunctionCall) otto.Value {
func (self *JSRE) connect(call otto.FunctionCall) otto.Value {
nodeURL, err := call.Argument(0).ToString()
if err != nil {
return otto.FalseValue()
@ -222,22 +192,12 @@ func (self *JSRE) require(call otto.FunctionCall) otto.Value {
return t
}
func (self *JSRE) execBlock(call otto.FunctionCall) otto.Value {
hash, err := call.Argument(0).ToString()
if err != nil {
return otto.UndefinedValue()
}
err = utils.BlockDo(self.ethereum, ethutil.Hex2Bytes(hash))
if err != nil {
fmt.Println(err)
func (self *JSRE) export(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) == 0 {
fmt.Println("err: require file name")
return otto.FalseValue()
}
return otto.TrueValue()
}
func (self *JSRE) export(call otto.FunctionCall) otto.Value {
fn, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)

View File

@ -16,7 +16,7 @@ function pp(object) {
str += " ]";
} else if(typeof(object) === "object") {
str += "{ ";
var last = Object.keys(object).sort().pop()
var last = Object.keys(object).pop()
for(var k in object) {
str += k + ": " + pp(object[k]);

View File

@ -6,7 +6,6 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/ui"
"github.com/ethereum/go-ethereum/xeth"
"github.com/obscuren/otto"
)
@ -96,17 +95,3 @@ func (self *JSEthereum) toVal(v interface{}) otto.Value {
return result
}
func (self *JSEthereum) Messages(object map[string]interface{}) otto.Value {
filter := ui.NewFilterFromMap(object, self.ethereum)
logs := filter.Find()
var jslogs []JSLog
for _, m := range logs {
jslogs = append(jslogs, NewJSLog(m))
}
v, _ := self.vm.ToValue(jslogs)
return v
}

View File

@ -1,6 +1,7 @@
package logger
import (
"math/big"
"time"
)
@ -54,7 +55,7 @@ func (l *P2PDisconnected) EventName() string {
type EthMinerNewBlock struct {
BlockHash string `json:"block_hash"`
BlockNumber int `json:"block_number"`
BlockNumber *big.Int `json:"block_number"`
ChainHeadHash string `json:"chain_head_hash"`
BlockPrevHash string `json:"block_prev_hash"`
LogEvent

View File

@ -52,10 +52,5 @@ func (self *Miner) Stop() {
}
func (self *Miner) HashRate() int64 {
var tot int64
for _, agent := range self.worker.agents {
tot += agent.Pow().GetHashrate()
}
return tot
return self.worker.HashRate()
}

View File

@ -5,16 +5,20 @@ import (
"math/big"
"sort"
"sync"
"time"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/state"
"gopkg.in/fatih/set.v0"
)
var jsonlogger = logger.NewJsonLogger()
type environment struct {
totalUsedGas *big.Int
state *state.StateDB
@ -111,6 +115,8 @@ func (self *worker) register(agent Agent) {
func (self *worker) update() {
events := self.mux.Subscribe(core.ChainEvent{}, core.NewMinedBlockEvent{})
timer := time.NewTicker(2 * time.Second)
out:
for {
select {
@ -129,6 +135,8 @@ out:
agent.Stop()
}
break out
case <-timer.C:
minerlogger.Debugln("Hash rate:", self.HashRate(), "Khash")
}
}
@ -141,7 +149,12 @@ func (self *worker) wait() {
block := self.current.block
if block.Number().Uint64() == work.Number && block.Nonce() == nil {
self.current.block.Header().Nonce = work.Nonce
jsonlogger.LogJson(&logger.EthMinerNewBlock{
BlockHash: ethutil.Bytes2Hex(block.Hash()),
BlockNumber: block.Number(),
ChainHeadHash: ethutil.Bytes2Hex(block.ParentHeaderHash),
BlockPrevHash: ethutil.Bytes2Hex(block.ParentHeaderHash),
})
if err := self.chain.InsertChain(types.Blocks{self.current.block}); err == nil {
self.mux.Post(core.NewMinedBlockEvent{self.current.block})
} else {
@ -197,7 +210,7 @@ gasLimit:
}
self.eth.TxPool().RemoveSet(remove)
self.current.coinbase.AddAmount(core.BlockReward)
self.current.coinbase.AddBalance(core.BlockReward)
self.current.state.Update(ethutil.Big0)
self.push()
@ -225,7 +238,7 @@ func (self *worker) commitUncle(uncle *types.Header) error {
}
uncleAccount := self.current.state.GetAccount(uncle.Coinbase)
uncleAccount.AddAmount(uncleReward)
uncleAccount.AddBalance(uncleReward)
self.current.coinbase.AddBalance(uncleReward)
@ -244,3 +257,12 @@ func (self *worker) commitTransaction(tx *types.Transaction) error {
return nil
}
func (self *worker) HashRate() int64 {
var tot int64
for _, agent := range self.agents {
tot += agent.Pow().GetHashrate()
}
return tot
}

View File

@ -20,18 +20,24 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/event/filter"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/ui"
"github.com/ethereum/go-ethereum/xeth"
)
const (
defaultGasPrice = "10000000000000"
defaultGas = "10000"
var (
defaultGasPrice = big.NewInt(10000000000000)
defaultGas = big.NewInt(10000)
filterTickerTime = 15 * time.Second
)
type EthereumApi struct {
xeth *xeth.XEth
eth *xeth.XEth
xethMu sync.RWMutex
mux *event.TypeMux
quit chan struct{}
filterManager *filter.FilterManager
@ -45,17 +51,21 @@ type EthereumApi struct {
register map[string][]*NewTxArgs
db ethutil.Database
defaultBlockAge int64
}
func NewEthereumApi(eth *xeth.XEth) *EthereumApi {
db, _ := ethdb.NewLDBDatabase("dapps")
api := &EthereumApi{
xeth: eth,
eth: eth,
mux: eth.Backend().EventMux(),
quit: make(chan struct{}),
filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
logs: make(map[int]*logFilter),
messages: make(map[int]*whisperFilter),
db: db,
defaultBlockAge: -1,
}
go api.filterManager.Start()
go api.start()
@ -63,6 +73,64 @@ func NewEthereumApi(eth *xeth.XEth) *EthereumApi {
return api
}
func (self *EthereumApi) setStateByBlockNumber(num int64) {
chain := self.xeth().Backend().ChainManager()
var block *types.Block
if self.defaultBlockAge < 0 {
num = chain.CurrentBlock().Number().Int64() + num + 1
}
block = chain.GetBlockByNumber(uint64(num))
if block != nil {
self.useState(state.New(block.Root(), self.xeth().Backend().Db()))
} else {
self.useState(chain.State())
}
}
func (self *EthereumApi) start() {
timer := time.NewTicker(filterTickerTime)
events := self.mux.Subscribe(core.ChainEvent{})
done:
for {
select {
case ev := <-events.Chan():
switch ev.(type) {
case core.ChainEvent:
if self.defaultBlockAge < 0 {
self.setStateByBlockNumber(self.defaultBlockAge)
}
}
case <-timer.C:
self.logMut.Lock()
self.messagesMut.Lock()
for id, filter := range self.logs {
if time.Since(filter.timeout) > 20*time.Second {
self.filterManager.UninstallFilter(id)
delete(self.logs, id)
}
}
for id, filter := range self.messages {
if time.Since(filter.timeout) > 20*time.Second {
self.xeth().Whisper().Unwatch(id)
delete(self.messages, id)
}
}
self.logMut.Unlock()
self.messagesMut.Unlock()
case <-self.quit:
break done
}
}
}
func (self *EthereumApi) stop() {
close(self.quit)
}
func (self *EthereumApi) Register(args string, reply *interface{}) error {
self.regmut.Lock()
defer self.regmut.Unlock()
@ -95,7 +163,7 @@ func (self *EthereumApi) WatchTx(args string, reply *interface{}) error {
func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error {
var id int
filter := core.NewFilter(self.xeth.Backend())
filter := core.NewFilter(self.xeth().Backend())
filter.SetOptions(toFilterOptions(args))
filter.LogsCallback = func(logs state.Logs) {
self.logMut.Lock()
@ -120,16 +188,12 @@ func (self *EthereumApi) UninstallFilter(id int, reply *interface{}) error {
func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error {
var id int
filter := core.NewFilter(self.xeth.Backend())
filter := core.NewFilter(self.xeth().Backend())
callback := func(block *types.Block) {
self.logMut.Lock()
defer self.logMut.Unlock()
if self.logs[id] == nil {
self.logs[id] = &logFilter{timeout: time.Now()}
}
self.logs[id].add(&state.StateLog{})
}
if args == "pending" {
@ -139,6 +203,7 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error
}
id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()}
*reply = id
return nil
@ -168,7 +233,7 @@ func (self *EthereumApi) Logs(id int, reply *interface{}) error {
}
func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error {
filter := core.NewFilter(self.xeth.Backend())
filter := core.NewFilter(self.xeth().Backend())
filter.SetOptions(toFilterOptions(args))
*reply = toLogs(filter.Find())
@ -177,41 +242,54 @@ func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error
}
func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
}
if args.BlockNumber > 0 {
*reply = p.xeth.BlockByNumber(args.BlockNumber)
// This seems a bit precarious Maybe worth splitting to discrete functions
if len(args.Hash) > 0 {
*reply = p.xeth().BlockByHash(args.Hash)
} else {
*reply = p.xeth.BlockByHash(args.Hash)
*reply = p.xeth().BlockByNumber(args.BlockNumber)
}
return nil
}
func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
if len(args.Gas) == 0 {
args.Gas = defaultGas
args.Gas = defaultGas.String()
}
if len(args.GasPrice) == 0 {
args.GasPrice = defaultGasPrice
args.GasPrice = defaultGasPrice.String()
}
// TODO if no_private_key then
if _, exists := p.register[args.From]; exists {
p.register[args.From] = append(p.register[args.From], args)
} else {
result, _ := p.xeth.Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data)
*reply = result
//if _, exists := p.register[args.From]; exists {
// p.register[args.From] = append(p.register[args.From], args)
//} else {
/*
account := accounts.Get(fromHex(args.From))
if account != nil {
if account.Unlocked() {
if !unlockAccount(account) {
return
}
}
result, _ := account.Transact(fromHex(args.To), fromHex(args.Value), fromHex(args.Gas), fromHex(args.GasPrice), fromHex(args.Data))
if len(result) > 0 {
*reply = toHex(result)
}
} else if _, exists := p.register[args.From]; exists {
p.register[ags.From] = append(p.register[args.From], args)
}
*/
result, _ := p.xeth().Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data)
*reply = result
//}
return nil
}
func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
result, err := p.xeth.Call( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data)
result, err := p.xeth().Call( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data)
if err != nil {
return err
}
@ -225,7 +303,7 @@ func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
if err != nil {
return err
}
result, _ := p.xeth.PushTx(args.Tx)
result, _ := p.xeth().PushTx(args.Tx)
*reply = result
return nil
}
@ -236,7 +314,7 @@ func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error {
return err
}
state := p.xeth.State().SafeGet(args.Address)
state := p.xeth().State().SafeGet(args.Address)
value := state.StorageString(args.Key)
var hx string
@ -258,42 +336,55 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) err
return err
}
*reply = p.xeth.State().SafeGet(args.Address).Storage()
*reply = p.xeth().State().SafeGet(args.Address).Storage()
return nil
}
func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
*reply = p.xeth.PeerCount()
*reply = p.xeth().PeerCount()
return nil
}
func (p *EthereumApi) GetIsListening(reply *interface{}) error {
*reply = p.xeth.IsListening()
*reply = p.xeth().IsListening()
return nil
}
func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
*reply = p.xeth.Coinbase()
*reply = p.xeth().Coinbase()
return nil
}
func (p *EthereumApi) Accounts(reply *interface{}) error {
*reply = p.xeth.Accounts()
*reply = p.xeth().Accounts()
return nil
}
func (p *EthereumApi) GetIsMining(reply *interface{}) error {
*reply = p.xeth.IsMining()
*reply = p.xeth().IsMining()
return nil
}
func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error {
*reply = p.xeth.SetMining(shouldmine)
*reply = p.xeth().SetMining(shouldmine)
return nil
}
func (p *EthereumApi) GetDefaultBlockAge(reply *interface{}) error {
*reply = p.defaultBlockAge
return nil
}
func (p *EthereumApi) SetDefaultBlockAge(defaultBlockAge int64, reply *interface{}) error {
p.defaultBlockAge = defaultBlockAge
p.setStateByBlockNumber(p.defaultBlockAge)
*reply = true
return nil
}
func (p *EthereumApi) BlockNumber(reply *interface{}) error {
*reply = p.xeth.Backend().ChainManager().CurrentBlock().Number()
*reply = p.xeth().Backend().ChainManager().CurrentBlock().Number()
return nil
}
@ -302,7 +393,7 @@ func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) err
if err != nil {
return err
}
*reply = p.xeth.TxCountAt(args.Address)
*reply = p.xeth().TxCountAt(args.Address)
return nil
}
@ -311,7 +402,7 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) err
if err != nil {
return err
}
state := p.xeth.State().SafeGet(args.Address)
state := p.xeth().State().SafeGet(args.Address)
*reply = toHex(state.Balance().Bytes())
return nil
}
@ -321,7 +412,7 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
if err != nil {
return err
}
*reply = p.xeth.CodeAt(args.Address)
*reply = p.xeth().CodeAt(args.Address)
return nil
}
@ -368,7 +459,7 @@ func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error {
}
func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error {
*reply = p.xeth.Whisper().NewIdentity()
*reply = p.xeth().Whisper().NewIdentity()
return nil
}
@ -377,12 +468,10 @@ func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) e
args.Fn = func(msg xeth.WhisperMessage) {
p.messagesMut.Lock()
defer p.messagesMut.Unlock()
if p.messages[id] == nil {
p.messages[id] = &whisperFilter{timeout: time.Now()}
}
p.messages[id].add(msg) // = append(p.messages[id], msg)
}
id = p.xeth.Whisper().Watch(args)
id = p.xeth().Whisper().Watch(args)
p.messages[id] = &whisperFilter{timeout: time.Now()}
*reply = id
return nil
}
@ -399,7 +488,7 @@ func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error {
}
func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{}) error {
err := p.xeth.Whisper().Post(args.Payload, args.To, args.From, args.Topic, args.Priority, args.Ttl)
err := p.xeth().Whisper().Post(args.Payload, args.To, args.From, args.Topic, args.Priority, args.Ttl)
if err != nil {
return err
}
@ -409,17 +498,17 @@ func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{})
}
func (p *EthereumApi) HasWhisperIdentity(args string, reply *interface{}) error {
*reply = p.xeth.Whisper().HasIdentity(args)
*reply = p.xeth().Whisper().HasIdentity(args)
return nil
}
func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error {
*reply = p.xeth.Whisper().Messages(id)
*reply = p.xeth().Whisper().Messages(id)
return nil
}
func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
// Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC
// Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC
rpclogger.DebugDetailf("%T %s", req.Params, req.Params)
switch req.Method {
case "eth_coinbase":
@ -434,6 +523,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
return err
}
return p.SetMining(args, reply)
case "eth_defaultBlock":
return p.GetDefaultBlockAge(reply)
case "eth_setDefaultBlock":
args, err := req.ToIntArgs()
if err != nil {
return err
}
return p.SetDefaultBlockAge(int64(args), reply)
case "eth_peerCount":
return p.GetPeerCount(reply)
case "eth_number":
@ -525,7 +622,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
}
return p.AllLogs(args, reply)
case "eth_gasPrice":
*reply = defaultGasPrice
*reply = toHex(defaultGasPrice.Bytes())
return nil
case "eth_register":
args, err := req.ToRegisterArgs()
@ -604,42 +701,34 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
}
return p.WhisperMessages(args, reply)
default:
return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method))
return NewErrorWithMessage(errNotImplemented, req.Method)
}
rpclogger.DebugDetailf("Reply: %T %s", reply, reply)
return nil
}
var filterTickerTime = 15 * time.Second
func (self *EthereumApi) xeth() *xeth.XEth {
self.xethMu.RLock()
defer self.xethMu.RUnlock()
func (self *EthereumApi) start() {
timer := time.NewTicker(filterTickerTime)
done:
for {
select {
case <-timer.C:
self.logMut.Lock()
self.messagesMut.Lock()
for id, filter := range self.logs {
if time.Since(filter.timeout) > 20*time.Second {
delete(self.logs, id)
}
return self.eth
}
for id, filter := range self.messages {
if time.Since(filter.timeout) > 20*time.Second {
delete(self.messages, id)
}
}
self.logMut.Unlock()
self.messagesMut.Unlock()
case <-self.quit:
break done
}
}
func (self *EthereumApi) useState(statedb *state.StateDB) {
self.xethMu.Lock()
defer self.xethMu.Unlock()
self.eth = self.eth.UseState(statedb)
}
func (self *EthereumApi) stop() {
close(self.quit)
func t(f ui.Frontend) {
// Call the password dialog
ret, err := f.Call("PasswordDialog")
if err != nil {
fmt.Println(err)
}
// Get the first argument
t, _ := ret.Get(0)
fmt.Println("return:", t)
}

View File

@ -7,6 +7,7 @@ import (
)
func TestFilterClose(t *testing.T) {
t.Skip()
api := &EthereumApi{
logs: make(map[int]*logFilter),
messages: make(map[int]*whisperFilter),

View File

@ -19,14 +19,7 @@ func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) {
obj.Hash = argstr
return
}
return NewErrorResponse(ErrorDecodeArgs)
}
func (obj *GetBlockArgs) requirements() error {
if obj.BlockNumber == 0 && obj.Hash == "" {
return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument")
}
return nil
return errDecodeArgs
}
type NewTxArgs struct {
@ -64,7 +57,7 @@ func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
return
}
return NewErrorResponse(ErrorDecodeArgs)
return errDecodeArgs
}
type PushTxArgs struct {
@ -77,12 +70,12 @@ func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) {
obj.Tx = arg0
return
}
return NewErrorResponse(ErrorDecodeArgs)
return errDecodeArgs
}
func (a *PushTxArgs) requirementsPushTx() error {
if a.Tx == "" {
return NewErrorResponse("PushTx requires a 'tx' as argument")
return NewErrorWithMessage(errArguments, "PushTx requires a 'tx' as argument")
}
return nil
}
@ -93,14 +86,14 @@ type GetStorageArgs struct {
func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
if err = json.Unmarshal(b, &obj.Address); err != nil {
return NewErrorResponse(ErrorDecodeArgs)
return errDecodeArgs
}
return
}
func (a *GetStorageArgs) requirements() error {
if len(a.Address) == 0 {
return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument")
}
return nil
}
@ -116,64 +109,39 @@ func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) {
obj.Address = arg0
return
}
return NewErrorResponse(ErrorDecodeArgs)
return errDecodeArgs
}
func (a *GetStateArgs) requirements() error {
if a.Address == "" {
return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument")
}
if a.Key == "" {
return NewErrorResponse("GetStorageAt requires an 'key' value as argument")
return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'key' value as argument")
}
return nil
}
type GetStorageAtRes struct {
Key string `json:"key"`
Value string `json:"value"`
}
type GetTxCountArgs struct {
Address string `json:"address"`
}
// type GetTxCountRes struct {
// Nonce int `json:"nonce"`
// }
func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := ""
if err = json.Unmarshal(b, &arg0); err == nil {
obj.Address = arg0
return
}
return NewErrorResponse("Could not determine JSON parameters")
return errDecodeArgs
}
func (a *GetTxCountArgs) requirements() error {
if a.Address == "" {
return NewErrorResponse("GetTxCountAt requires an 'address' value as argument")
return NewErrorWithMessage(errArguments, "GetTxCountAt requires an 'address' value as argument")
}
return nil
}
// type GetPeerCountRes struct {
// PeerCount int `json:"peerCount"`
// }
// type GetListeningRes struct {
// IsListening bool `json:"isListening"`
// }
// type GetCoinbaseRes struct {
// Coinbase string `json:"coinbase"`
// }
// type GetMiningRes struct {
// IsMining bool `json:"isMining"`
// }
type GetBalanceArgs struct {
Address string
}
@ -184,21 +152,16 @@ func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
obj.Address = arg0
return
}
return NewErrorResponse("Could not determine JSON parameters")
return errDecodeArgs
}
func (a *GetBalanceArgs) requirements() error {
if a.Address == "" {
return NewErrorResponse("GetBalanceAt requires an 'address' value as argument")
return NewErrorWithMessage(errArguments, "GetBalanceAt requires an 'address' value as argument")
}
return nil
}
type BalanceRes struct {
Balance string `json:"balance"`
Address string `json:"address"`
}
type GetCodeAtArgs struct {
Address string
}
@ -209,12 +172,12 @@ func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) {
obj.Address = arg0
return
}
return NewErrorResponse(ErrorDecodeArgs)
return errDecodeArgs
}
func (a *GetCodeAtArgs) requirements() error {
if a.Address == "" {
return NewErrorResponse("GetCodeAt requires an 'address' value as argument")
return NewErrorWithMessage(errArguments, "GetCodeAt requires an 'address' value as argument")
}
return nil
}
@ -225,7 +188,7 @@ type Sha3Args struct {
func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) {
if err = json.Unmarshal(b, &obj.Data); err != nil {
return NewErrorResponse(ErrorDecodeArgs)
return errDecodeArgs
}
return
}
@ -234,7 +197,7 @@ type FilterOptions struct {
Earliest int64
Latest int64
Address interface{}
Topic []string
Topic []interface{}
Skip int
Max int
}
@ -257,10 +220,20 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions {
opts.Earliest = options.Earliest
opts.Latest = options.Latest
opts.Topics = make([][]byte, len(options.Topic))
for i, topic := range options.Topic {
opts.Topics[i] = fromHex(topic)
topics := make([][][]byte, len(options.Topic))
for i, topicDat := range options.Topic {
if slice, ok := topicDat.([]interface{}); ok {
topics[i] = make([][]byte, len(slice))
for j, topic := range slice {
topics[i][j] = fromHex(topic.(string))
}
} else if str, ok := topicDat.(string); ok {
topics[i] = make([][]byte, 1)
topics[i][0] = fromHex(str)
}
}
opts.Topics = topics
return opts
}
@ -277,10 +250,10 @@ type DbArgs struct {
func (a *DbArgs) requirements() error {
if len(a.Database) == 0 {
return NewErrorResponse("DbPutArgs requires an 'Database' value as argument")
return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Database' value as argument")
}
if len(a.Key) == 0 {
return NewErrorResponse("DbPutArgs requires an 'Key' value as argument")
return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Key' value as argument")
}
return nil
}

View File

@ -29,8 +29,8 @@ import (
var rpchttplogger = logger.NewLogger("RPC-HTTP")
var JSON rpc.JsonWrapper
func NewRpcHttpServer(pipe *xeth.XEth, port int) (*RpcHttpServer, error) {
sport := fmt.Sprintf("127.0.0.1:%d", port)
func NewRpcHttpServer(pipe *xeth.XEth, address string, port int) (*RpcHttpServer, error) {
sport := fmt.Sprintf("%s:%d", address, port)
l, err := net.Listen("tcp", sport)
if err != nil {
return nil, err
@ -41,6 +41,7 @@ func NewRpcHttpServer(pipe *xeth.XEth, port int) (*RpcHttpServer, error) {
quit: make(chan bool),
pipe: pipe,
port: port,
addr: address,
}, nil
}
@ -49,6 +50,7 @@ type RpcHttpServer struct {
listener net.Listener
pipe *xeth.XEth
port int
addr string
}
func (s *RpcHttpServer) exitHandler() {
@ -69,7 +71,7 @@ func (s *RpcHttpServer) Stop() {
}
func (s *RpcHttpServer) Start() {
rpchttplogger.Infof("Starting RPC-HTTP server on port %d", s.port)
rpchttplogger.Infof("Starting RPC-HTTP server on %s:%d", s.addr, s.port)
go s.exitHandler()
api := rpc.NewEthereumApi(s.pipe)
@ -92,7 +94,7 @@ func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler {
reqParsed, reqerr := JSON.ParseRequestBody(req)
if reqerr != nil {
jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest}
jsonerr := &rpc.RpcErrorObject{-32700, "Error: Could not parse request"}
JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
return
}

View File

@ -25,12 +25,11 @@ import (
"github.com/ethereum/go-ethereum/xeth"
)
const (
ErrorArguments = "Error: Insufficient arguments"
ErrorNotImplemented = "Error: Method not implemented"
ErrorUnknown = "Error: Unknown error"
ErrorParseRequest = "Error: Could not parse request"
ErrorDecodeArgs = "Error: Could not decode arguments"
var (
errArguments = errors.New("Error: Insufficient arguments")
errNotImplemented = errors.New("Error: Method not implemented")
errUnknown = errors.New("Error: Unknown error")
errDecodeArgs = errors.New("Error: Could not decode arguments")
)
type RpcRequest struct {
@ -58,76 +57,72 @@ type RpcErrorObject struct {
// Data interface{} `json:"data"`
}
func NewErrorResponse(msg string) error {
return errors.New(msg)
}
func NewErrorResponseWithError(msg string, err error) error {
return fmt.Errorf("%s: %v", msg, err)
func NewErrorWithMessage(err error, msg string) error {
return fmt.Errorf("%s: %s", err.Error(), msg)
}
func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(Sha3Args)
r := bytes.NewReader(req.Params[0])
if err := json.NewDecoder(r).Decode(args); err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(GetBlockArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(NewTxArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(PushTxArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToGetStateArgs() (*GetStateArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(GetStateArgs)
@ -135,234 +130,241 @@ func (req *RpcRequest) ToGetStateArgs() (*GetStateArgs, error) {
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToStorageAtArgs() (*GetStorageArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(GetStorageArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(GetTxCountArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToGetBalanceArgs() (*GetBalanceArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(GetBalanceArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(GetCodeAtArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToBoolArgs() (bool, error) {
if len(req.Params) < 1 {
return false, NewErrorResponse(ErrorArguments)
return false, errArguments
}
var args bool
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return false, NewErrorResponse(ErrorDecodeArgs)
return false, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToIntArgs() (int, error) {
if len(req.Params) < 1 {
return 0, errArguments
}
var args int
if err := json.Unmarshal(req.Params[0], &args); err != nil {
return 0, errArguments
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToCompileArgs() (string, error) {
if len(req.Params) < 1 {
return "", NewErrorResponse(ErrorArguments)
return "", errArguments
}
var args string
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return "", NewErrorResponse(ErrorDecodeArgs)
return "", errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToFilterArgs() (*FilterOptions, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
args := new(FilterOptions)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorResponse(ErrorDecodeArgs)
return nil, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToFilterStringArgs() (string, error) {
if len(req.Params) < 1 {
return "", NewErrorResponse(ErrorArguments)
return "", errArguments
}
var args string
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return "", NewErrorResponse(ErrorDecodeArgs)
return "", errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToUninstallFilterArgs() (int, error) {
if len(req.Params) < 1 {
return 0, NewErrorResponse(ErrorArguments)
return 0, errArguments
}
var args int
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return 0, NewErrorResponse(ErrorDecodeArgs)
return 0, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToFilterChangedArgs() (int, error) {
if len(req.Params) < 1 {
return 0, NewErrorResponse(ErrorArguments)
return 0, errArguments
}
var id int
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(&id)
if err != nil {
return 0, NewErrorResponse(ErrorDecodeArgs)
return 0, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", id, id)
return id, nil
}
func (req *RpcRequest) ToDbPutArgs() (*DbArgs, error) {
if len(req.Params) < 3 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
var args DbArgs
err := json.Unmarshal(req.Params[0], &args.Database)
if err != nil {
return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
err = json.Unmarshal(req.Params[1], &args.Key)
if err != nil {
return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
err = json.Unmarshal(req.Params[2], &args.Value)
if err != nil {
return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
rpclogger.DebugDetailf("%T %v", args, args)
return &args, nil
}
func (req *RpcRequest) ToDbGetArgs() (*DbArgs, error) {
if len(req.Params) < 2 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
var args DbArgs
err := json.Unmarshal(req.Params[0], &args.Database)
if err != nil {
return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
err = json.Unmarshal(req.Params[1], &args.Key)
if err != nil {
return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
rpclogger.DebugDetailf("%T %v", args, args)
return &args, nil
}
func (req *RpcRequest) ToWhisperFilterArgs() (*xeth.Options, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
var args xeth.Options
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
rpclogger.DebugDetailf("%T %v", args, args)
return &args, nil
}
func (req *RpcRequest) ToIdArgs() (int, error) {
if len(req.Params) < 1 {
return 0, NewErrorResponse(ErrorArguments)
return 0, errArguments
}
var id int
err := json.Unmarshal(req.Params[0], &id)
if err != nil {
return 0, NewErrorResponse(ErrorDecodeArgs)
return 0, errDecodeArgs
}
rpclogger.DebugDetailf("%T %v", id, id)
return id, nil
}
func (req *RpcRequest) ToWhisperPostArgs() (*WhisperMessageArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
return nil, errArguments
}
var args WhisperMessageArgs
@ -370,13 +372,13 @@ func (req *RpcRequest) ToWhisperPostArgs() (*WhisperMessageArgs, error) {
if err != nil {
return nil, err
}
rpclogger.DebugDetailf("%T %v", args, args)
return &args, nil
}
func (req *RpcRequest) ToWhisperHasIdentityArgs() (string, error) {
if len(req.Params) < 1 {
return "", NewErrorResponse(ErrorArguments)
return "", errArguments
}
var args string
@ -384,13 +386,13 @@ func (req *RpcRequest) ToWhisperHasIdentityArgs() (string, error) {
if err != nil {
return "", err
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToRegisterArgs() (string, error) {
if len(req.Params) < 1 {
return "", NewErrorResponse(ErrorArguments)
return "", errArguments
}
var args string
@ -398,13 +400,13 @@ func (req *RpcRequest) ToRegisterArgs() (string, error) {
if err != nil {
return "", err
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}
func (req *RpcRequest) ToWatchTxArgs() (string, error) {
if len(req.Params) < 1 {
return "", NewErrorResponse(ErrorArguments)
return "", errArguments
}
var args string
@ -412,6 +414,6 @@ func (req *RpcRequest) ToWatchTxArgs() (string, error) {
if err != nil {
return "", err
}
rpclogger.DebugDetailf("%T %v", args, args)
return args, nil
}

View File

@ -82,7 +82,7 @@ type RpcServer interface {
type Log struct {
Address string `json:"address"`
Topic []string `json:"topics"`
Topic []string `json:"topic"`
Data string `json:"data"`
Number uint64 `json:"number"`
}
@ -108,6 +108,7 @@ func toLogs(logs state.Logs) (ls []Log) {
type whisperFilter struct {
messages []xeth.WhisperMessage
timeout time.Time
id int
}
func (w *whisperFilter) add(msgs ...xeth.WhisperMessage) {
@ -123,6 +124,7 @@ func (w *whisperFilter) get() []xeth.WhisperMessage {
type logFilter struct {
logs state.Logs
timeout time.Time
id int
}
func (l *logFilter) add(logs ...state.Log) {

View File

@ -1,121 +0,0 @@
/*
This file is part of go-ethereum
go-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
go-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
package rpcws
import (
"fmt"
"net"
"net/http"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/xeth"
"golang.org/x/net/websocket"
)
var wslogger = logger.NewLogger("RPC-WS")
var JSON rpc.JsonWrapper
type WebSocketServer struct {
pipe *xeth.XEth
port int
doneCh chan bool
listener net.Listener
}
func NewWebSocketServer(pipe *xeth.XEth, port int) (*WebSocketServer, error) {
sport := fmt.Sprintf(":%d", port)
l, err := net.Listen("tcp", sport)
if err != nil {
return nil, err
}
return &WebSocketServer{
pipe,
port,
make(chan bool),
l,
}, nil
}
func (self *WebSocketServer) handlerLoop() {
for {
select {
case <-self.doneCh:
wslogger.Infoln("Shutdown RPC-WS server")
return
}
}
}
func (self *WebSocketServer) Stop() {
close(self.doneCh)
}
func (self *WebSocketServer) Start() {
wslogger.Infof("Starting RPC-WS server on port %d", self.port)
go self.handlerLoop()
api := rpc.NewEthereumApi(self.pipe)
h := self.apiHandler(api)
http.Handle("/ws", h)
err := http.Serve(self.listener, nil)
if err != nil {
wslogger.Errorln("Error on RPC-WS interface:", err)
}
}
func (s *WebSocketServer) apiHandler(api *rpc.EthereumApi) http.Handler {
fn := func(w http.ResponseWriter, req *http.Request) {
h := sockHandler(api)
s := websocket.Server{Handler: h}
s.ServeHTTP(w, req)
}
return http.HandlerFunc(fn)
}
func sockHandler(api *rpc.EthereumApi) websocket.Handler {
var jsonrpcver string = "2.0"
fn := func(conn *websocket.Conn) {
for {
wslogger.Debugln("Handling connection")
var reqParsed rpc.RpcRequest
// reqParsed, reqerr := JSON.ParseRequestBody(conn.Request())
if err := websocket.JSON.Receive(conn, &reqParsed); err != nil {
jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest}
JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
continue
}
var response interface{}
reserr := api.GetRequestReply(&reqParsed, &response)
if reserr != nil {
wslogger.Warnln(reserr)
jsonerr := &rpc.RpcErrorObject{-32603, reserr.Error()}
JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
continue
}
wslogger.Debugf("Generated response: %T %s", response, response)
JSON.Send(conn, &rpc.RpcSuccessResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Result: response})
}
}
return websocket.Handler(fn)
}

View File

@ -20,7 +20,7 @@ type World struct {
Accounts map[string]Account `json:"accounts"`
}
func (self *StateDB) Dump() []byte {
func (self *StateDB) RawDump() World {
world := World{
Root: ethutil.Bytes2Hex(self.trie.Root()),
Accounts: make(map[string]Account),
@ -35,12 +35,15 @@ func (self *StateDB) Dump() []byte {
storageIt := stateObject.State.trie.Iterator()
for storageIt.Next() {
account.Storage[ethutil.Bytes2Hex(it.Key)] = ethutil.Bytes2Hex(it.Value)
account.Storage[ethutil.Bytes2Hex(storageIt.Key)] = ethutil.Bytes2Hex(storageIt.Value)
}
world.Accounts[ethutil.Bytes2Hex(it.Key)] = account
}
return world
}
json, err := json.MarshalIndent(world, "", " ")
func (self *StateDB) Dump() []byte {
json, err := json.MarshalIndent(self.RawDump(), "", " ")
if err != nil {
fmt.Println("dump err", err)
}

View File

@ -19,6 +19,14 @@ func (self Code) String() string {
type Storage map[string]*ethutil.Value
func (self Storage) String() (str string) {
for key, value := range self {
str += fmt.Sprintf("%X : %X\n", key, value.Bytes())
}
return
}
func (self Storage) Copy() Storage {
cpy := make(Storage)
for key, value := range self {
@ -119,10 +127,9 @@ func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value {
}
func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) {
self.SetState(key.Bytes(), value)
self.dirty = true
}
func (self *StateObject) Storage() map[string]*ethutil.Value {
func (self *StateObject) Storage() Storage {
return self.storage
}
@ -172,20 +179,22 @@ func (c *StateObject) AddBalance(amount *big.Int) {
statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount)
}
func (c *StateObject) AddAmount(amount *big.Int) { c.AddBalance(amount) }
func (c *StateObject) SubBalance(amount *big.Int) {
c.SetBalance(new(big.Int).Sub(c.balance, amount))
statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount)
}
func (c *StateObject) SubAmount(amount *big.Int) { c.SubBalance(amount) }
func (c *StateObject) SetBalance(amount *big.Int) {
c.balance = amount
c.dirty = true
}
func (c *StateObject) St() Storage {
return c.storage
}
//
// Gas setters and getters
//
@ -198,7 +207,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error {
return fmt.Errorf("insufficient amount: %v, %v", c.balance, total)
}
c.SubAmount(total)
c.SubBalance(total)
c.dirty = true
@ -221,7 +230,7 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error {
rGas := new(big.Int).Set(gas)
rGas.Mul(rGas, price)
self.AddAmount(rGas)
self.AddBalance(rGas)
self.dirty = true

View File

@ -54,7 +54,7 @@ func (self *StateDB) Refund(addr []byte, gas *big.Int) {
// Retrieve the balance from the given address or 0 if object not found
func (self *StateDB) GetBalance(addr []byte) *big.Int {
stateObject := self.GetStateObject(addr)
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
return stateObject.balance
}
@ -63,14 +63,14 @@ func (self *StateDB) GetBalance(addr []byte) *big.Int {
}
func (self *StateDB) AddBalance(addr []byte, amount *big.Int) {
stateObject := self.GetStateObject(addr)
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.AddBalance(amount)
}
}
func (self *StateDB) GetNonce(addr []byte) uint64 {
stateObject := self.GetStateObject(addr)
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
return stateObject.nonce
}
@ -79,7 +79,7 @@ func (self *StateDB) GetNonce(addr []byte) uint64 {
}
func (self *StateDB) GetCode(addr []byte) []byte {
stateObject := self.GetStateObject(addr)
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
return stateObject.code
}
@ -88,7 +88,7 @@ func (self *StateDB) GetCode(addr []byte) []byte {
}
func (self *StateDB) GetState(a, b []byte) []byte {
stateObject := self.GetStateObject(a)
stateObject := self.GetOrNewStateObject(a)
if stateObject != nil {
return stateObject.GetState(b).Bytes()
}
@ -97,28 +97,28 @@ func (self *StateDB) GetState(a, b []byte) []byte {
}
func (self *StateDB) SetNonce(addr []byte, nonce uint64) {
stateObject := self.GetStateObject(addr)
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.SetNonce(nonce)
}
}
func (self *StateDB) SetCode(addr, code []byte) {
stateObject := self.GetStateObject(addr)
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.SetCode(code)
}
}
func (self *StateDB) SetState(addr, key []byte, value interface{}) {
stateObject := self.GetStateObject(addr)
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.SetState(key, ethutil.NewValue(value))
}
}
func (self *StateDB) Delete(addr []byte) bool {
stateObject := self.GetStateObject(addr)
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.MarkForDeletion()

View File

@ -1,77 +1 @@
package ui
import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ethutil"
)
func fromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" {
s = s[2:]
}
return ethutil.Hex2Bytes(s)
}
return nil
}
func NewFilterFromMap(object map[string]interface{}, eth core.Backend) *core.Filter {
filter := core.NewFilter(eth)
if object["earliest"] != nil {
val := ethutil.NewValue(object["earliest"])
filter.SetEarliestBlock(val.Int())
}
if object["latest"] != nil {
val := ethutil.NewValue(object["latest"])
filter.SetLatestBlock(val.Int())
}
if object["address"] != nil {
//val := ethutil.NewValue(object["address"])
//filter.SetAddress(fromHex(val.Str()))
}
if object["max"] != nil {
val := ethutil.NewValue(object["max"])
filter.SetMax(int(val.Uint()))
}
if object["skip"] != nil {
val := ethutil.NewValue(object["skip"])
filter.SetSkip(int(val.Uint()))
}
if object["topics"] != nil {
filter.SetTopics(MakeTopics(object["topics"]))
}
return filter
}
// Conversion methodn
func mapToAccountChange(m map[string]interface{}) (d core.AccountChange) {
if str, ok := m["id"].(string); ok {
d.Address = fromHex(str)
}
if str, ok := m["at"].(string); ok {
d.StateAddress = fromHex(str)
}
return
}
// data can come in in the following formats:
// ["aabbccdd", {id: "ccddee", at: "11223344"}], "aabbcc", {id: "ccddee", at: "1122"}
func MakeTopics(v interface{}) (d [][]byte) {
if str, ok := v.(string); ok {
d = append(d, fromHex(str))
} else if slice, ok := v.([]string); ok {
for _, item := range slice {
d = append(d, fromHex(item))
}
}
return
}

18
ui/frontend.go Normal file
View File

@ -0,0 +1,18 @@
package ui
// ReturnInterface is returned by the Intercom interface when a method is called
type ReturnInterface interface {
Get(i int) (interface{}, error)
Size() int
}
// Frontend is the basic interface for calling arbitrary methods on something that
// implements a front end (GUI, CLI, etc)
type Frontend interface {
// Checks whether a specific method is implemented
Supports(method string) bool
// Call calls the given method on interface it implements. This will return
// an error with errNotImplemented if the method hasn't been implemented
// and will return a ReturnInterface if it does.
Call(method string) (ReturnInterface, error)
}

View File

@ -1,30 +1 @@
package qt
import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ui"
"github.com/obscuren/qml"
)
func NewFilterFromMap(object map[string]interface{}, eth core.Backend) *core.Filter {
filter := ui.NewFilterFromMap(object, eth)
if object["topics"] != nil {
filter.SetTopics(makeTopics(object["topics"]))
}
return filter
}
func makeTopics(v interface{}) (d [][]byte) {
if qList, ok := v.(*qml.List); ok {
var s []string
qList.Convert(&s)
d = ui.MakeTopics(s)
} else if str, ok := v.(string); ok {
d = ui.MakeTopics(str)
}
return
}

View File

@ -16,6 +16,8 @@ type Vm struct {
logStr string
err error
// For logging
debug bool
Dbg Debugger
@ -32,7 +34,7 @@ func New(env Environment) *Vm {
lt = LogTyDiff
}
return &Vm{env: env, logTy: lt, Recoverable: true}
return &Vm{debug: false, env: env, logTy: lt, Recoverable: true}
}
func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
@ -664,6 +666,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
}
addr = ref.Address()
fmt.Printf("CREATE %X\n", addr)
stack.Push(ethutil.BigD(addr))
}
@ -727,7 +730,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
self.Printf(" => (%x) %v", receiver.Address()[:4], balance)
receiver.AddAmount(balance)
receiver.AddBalance(balance)
statedb.Delete(context.Address())
fallthrough
@ -828,7 +831,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
// 0 => non 0
mult = ethutil.Big3
} else if len(val) > 0 && len(y.Bytes()) == 0 {
statedb.Refund(caller.Address(), GasSStoreRefund)
statedb.Refund(self.env.Origin(), GasSStoreRefund)
mult = ethutil.Big0
} else {
@ -937,18 +940,22 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *
}
func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
self.logStr += fmt.Sprintf(format, v...)
}
}
return self
}
func (self *Vm) Endl() VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
vmlogger.Debugln(self.logStr)
self.logStr = ""
}
}
return self
}

View File

@ -50,6 +50,7 @@ type RuntimeData struct {
timestamp int64
code *byte
codeSize uint64
codeHash i256
}
func hash2llvm(h []byte) i256 {
@ -180,6 +181,7 @@ func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *bi
self.data.timestamp = self.env.Time()
self.data.code = getDataPtr(code)
self.data.codeSize = uint64(len(code))
self.data.codeHash = hash2llvm(crypto.Sha3(code)) // TODO: Get already computed hash?
jit := C.evmjit_create()
retCode := C.evmjit_run(jit, unsafe.Pointer(&self.data), unsafe.Pointer(self))
@ -197,12 +199,12 @@ func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *bi
receiverAddr := llvm2hashRef(bswap(&self.data.address))
receiver := state.GetOrNewStateObject(receiverAddr)
balance := state.GetBalance(me.Address())
receiver.AddAmount(balance)
receiver.AddBalance(balance)
state.Delete(me.Address())
}
}
C.evmjit_destroy(jit);
C.evmjit_destroy(jit)
return
}
@ -278,7 +280,7 @@ func env_blockhash(_vm unsafe.Pointer, _number unsafe.Pointer, _result unsafe.Po
}
//export env_call
func env_call(_vm unsafe.Pointer, _gas unsafe.Pointer, _receiveAddr unsafe.Pointer, _value unsafe.Pointer, inDataPtr unsafe.Pointer, inDataLen uint64, outDataPtr *byte, outDataLen uint64, _codeAddr unsafe.Pointer) bool {
func env_call(_vm unsafe.Pointer, _gas *int64, _receiveAddr unsafe.Pointer, _value unsafe.Pointer, inDataPtr unsafe.Pointer, inDataLen uint64, outDataPtr *byte, outDataLen uint64, _codeAddr unsafe.Pointer) bool {
vm := (*JitVm)(_vm)
//fmt.Printf("env_call (depth %d)\n", vm.Env().Depth())
@ -297,8 +299,7 @@ func env_call(_vm unsafe.Pointer, _gas unsafe.Pointer, _receiveAddr unsafe.Point
inData := C.GoBytes(inDataPtr, C.int(inDataLen))
outData := llvm2bytesRef(outDataPtr, outDataLen)
codeAddr := llvm2hash((*i256)(_codeAddr))
llvmGas := (*i256)(_gas)
gas := llvm2big(llvmGas)
gas := big.NewInt(*_gas)
var out []byte
var err error
if bytes.Equal(codeAddr, receiveAddr) {
@ -306,7 +307,7 @@ func env_call(_vm unsafe.Pointer, _gas unsafe.Pointer, _receiveAddr unsafe.Point
} else {
out, err = vm.env.CallCode(vm.me, codeAddr, inData, gas, vm.price, value)
}
*llvmGas = big2llvm(gas)
*_gas = gas.Int64()
if err == nil {
copy(outData, out)
return true
@ -317,7 +318,7 @@ func env_call(_vm unsafe.Pointer, _gas unsafe.Pointer, _receiveAddr unsafe.Point
}
//export env_create
func env_create(_vm unsafe.Pointer, _gas unsafe.Pointer, _value unsafe.Pointer, initDataPtr unsafe.Pointer, initDataLen uint64, _result unsafe.Pointer) {
func env_create(_vm unsafe.Pointer, _gas *int64, _value unsafe.Pointer, initDataPtr unsafe.Pointer, initDataLen uint64, _result unsafe.Pointer) {
vm := (*JitVm)(_vm)
value := llvm2big((*i256)(_value))
@ -325,9 +326,7 @@ func env_create(_vm unsafe.Pointer, _gas unsafe.Pointer, _value unsafe.Pointer,
result := (*i256)(_result)
*result = i256{}
llvmGas := (*i256)(_gas)
gas := llvm2big(llvmGas)
gas := big.NewInt(*_gas)
ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value)
if suberr == nil {
dataGas := big.NewInt(int64(len(ret))) // TODO: Nto the best design. env.Create can do it, it has the reference to gas counter
@ -335,7 +334,7 @@ func env_create(_vm unsafe.Pointer, _gas unsafe.Pointer, _value unsafe.Pointer,
gas.Sub(gas, dataGas)
*result = hash2llvm(ref.Address())
}
*llvmGas = big2llvm(gas)
*_gas = gas.Int64()
}
//export env_log
@ -358,7 +357,7 @@ func env_log(_vm unsafe.Pointer, dataPtr unsafe.Pointer, dataLen uint64, _topic1
topics = append(topics, llvm2hash((*i256)(_topic4)))
}
vm.Env().AddLog(state.NewLog(vm.me.Address(), topics, data))
vm.Env().AddLog(state.NewLog(vm.me.Address(), topics, data, vm.env.BlockNumber().Uint64()))
}
//export env_extcode

View File

@ -127,6 +127,10 @@ func (self *Whisper) Watch(opts Filter) int {
})
}
func (self *Whisper) Unwatch(id int) {
self.filters.Uninstall(id)
}
func (self *Whisper) Messages(id int) (messages []*Message) {
filter := self.filters.Get(id)
if filter != nil {

View File

@ -4,18 +4,19 @@ import "github.com/ethereum/go-ethereum/state"
type State struct {
xeth *XEth
state *state.StateDB
}
func NewState(xeth *XEth) *State {
return &State{xeth}
func NewState(xeth *XEth, statedb *state.StateDB) *State {
return &State{xeth, statedb}
}
func (self *State) State() *state.StateDB {
return self.xeth.chainManager.TransState()
return self.state
}
func (self *State) Get(addr string) *Object {
return &Object{self.State().GetStateObject(fromHex(addr))}
return &Object{self.state.GetStateObject(fromHex(addr))}
}
func (self *State) SafeGet(addr string) *Object {
@ -23,7 +24,7 @@ func (self *State) SafeGet(addr string) *Object {
}
func (self *State) safeGet(addr string) *state.StateObject {
object := self.State().GetStateObject(fromHex(addr))
object := self.state.GetStateObject(fromHex(addr))
if object == nil {
object = state.NewStateObject(fromHex(addr), self.xeth.eth.Db())
}

View File

@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/whisper"
)
@ -54,13 +55,26 @@ func New(eth Backend) *XEth {
whisper: NewWhisper(eth.Whisper()),
miner: eth.Miner(),
}
xeth.state = NewState(xeth)
xeth.state = NewState(xeth, xeth.chainManager.TransState())
return xeth
}
func (self *XEth) Backend() Backend { return self.eth }
func (self *XEth) UseState(statedb *state.StateDB) *XEth {
xeth := &XEth{
eth: self.eth,
blockProcessor: self.blockProcessor,
chainManager: self.chainManager,
whisper: self.whisper,
miner: self.miner,
}
xeth.state = NewState(xeth, statedb)
return xeth
}
func (self *XEth) State() *State { return self.state }
func (self *XEth) Whisper() *Whisper { return self.whisper }
func (self *XEth) Miner() *miner.Miner { return self.miner }
@ -229,7 +243,7 @@ func (self *XEth) Call(toStr, valueStr, gasStr, gasPriceStr, dataStr string) (st
}
var (
statedb = self.chainManager.TransState()
statedb = self.State().State() //self.chainManager.TransState()
key = self.eth.KeyManager().KeyPair()
from = statedb.GetOrNewStateObject(key.Address())
block = self.chainManager.CurrentBlock()
@ -277,7 +291,7 @@ func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string)
}
var err error
state := self.eth.ChainManager().TransState()
state := self.eth.ChainManager().TxState()
if balance := state.GetBalance(key.Address()); balance.Cmp(tx.Value()) < 0 {
return "", fmt.Errorf("insufficient balance. balance=%v tx=%v", balance, tx.Value())
}
@ -286,14 +300,6 @@ func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string)
tx.SetNonce(nonce)
tx.Sign(key.PrivateKey)
//fmt.Printf("create tx: %x %v\n", tx.Hash()[:4], tx.Nonce())
// Do some pre processing for our "pre" events and hooks
block := self.chainManager.NewBlock(key.Address())
coinbase := state.GetOrNewStateObject(key.Address())
coinbase.SetGasPool(block.GasLimit())
self.blockProcessor.ApplyTransactions(coinbase, state, block, types.Transactions{tx}, true)
err = self.eth.TxPool().Add(tx)
if err != nil {
return "", err