diff --git a/.travis.yml b/.travis.yml
index 1b31048267..c4e39b05ea 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,20 @@
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:
+ # - go get code.google.com/p/go.tools/cmd/goimports
+ # - go get github.com/golang/lint/golint
# - go get golang.org/x/tools/cmd/vet
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
- go get github.com/mattn/goveralls
before_script:
+ # - gofmt -l -w .
+ # - goimports -l -w .
+ # - golint .
# - go vet ./...
# - go test -race ./...
script:
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 9b73065309..b66ea932fe 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -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"
diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE
deleted file mode 100644
index 18527a28fb..0000000000
--- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE
+++ /dev/null
@@ -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.
diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/LICENSE b/Godeps/_workspace/src/github.com/kardianos/osext/LICENSE
new file mode 100644
index 0000000000..7448756763
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kardianos/osext/LICENSE
@@ -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.
diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/README.md b/Godeps/_workspace/src/github.com/kardianos/osext/README.md
new file mode 100644
index 0000000000..820e1ecb54
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/kardianos/osext/README.md
@@ -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.
diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext.go
similarity index 87%
rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go
rename to Godeps/_workspace/src/github.com/kardianos/osext/osext.go
index 37efbb2210..4ed4b9aa33 100644
--- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go
+++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext.go
@@ -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()
-}
diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go
similarity index 51%
rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go
rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go
index 4468a73a7f..655750c542 100644
--- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go
+++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go
@@ -5,16 +5,16 @@
package osext
import (
- "syscall"
- "os"
- "strconv"
+ "os"
+ "strconv"
+ "syscall"
)
func executable() (string, error) {
- f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
- if err != nil {
- return "", err
- }
- defer f.Close()
- return syscall.Fd2path(int(f.Fd()))
+ f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+ return syscall.Fd2path(int(f.Fd()))
}
diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go
similarity index 74%
rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go
rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go
index 546fec9155..a50021ad53 100644
--- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go
+++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go
@@ -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)
}
diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go
similarity index 100%
rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go
rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go
diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go
similarity index 100%
rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go
rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go
diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go
similarity index 100%
rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go
rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go
diff --git a/accounts/account_manager.go b/accounts/account_manager.go
index da0bd89004..3e9fa77991 100644
--- a/accounts/account_manager.go
+++ b/accounts/account_manager.go
@@ -34,33 +34,62 @@ 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
}
type AccountManager struct {
- keyStore crypto.KeyStore2
+ 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,
+ 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()
+}
diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go
index 30e8c62855..44d1d72f17 100644
--- a/accounts/accounts_test.go
+++ b/accounts/accounts_test.go
@@ -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)
+ }
+ }
}
diff --git a/cmd/ethereum/flags.go b/cmd/ethereum/flags.go
index 577bee4426..7d410c8e45 100644
--- a/cmd/ethereum/flags.go
+++ b/cmd/ethereum/flags.go
@@ -26,10 +26,10 @@ import (
"fmt"
"log"
"os"
- "os/user"
"path"
"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"
@@ -79,12 +79,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
@@ -107,7 +102,7 @@ func Init() {
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)")
diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go
index 53a558a99c..45e6f7b935 100644
--- a/cmd/ethereum/main.go
+++ b/cmd/ethereum/main.go
@@ -37,7 +37,7 @@ import (
const (
ClientIdentifier = "Ethereum(G)"
- Version = "0.8.4"
+ Version = "0.8.6"
)
var clilogger = logger.NewLogger("CLI")
diff --git a/cmd/mist/assets/examples/coin.html b/cmd/mist/assets/examples/coin.html
index cb9d471de5..509a9aeeb3 100644
--- a/cmd/mist/assets/examples/coin.html
+++ b/cmd/mist/assets/examples/coin.html
@@ -14,10 +14,12 @@
- Amount:
+ Address:
+ Amount:
Send
+
@@ -58,7 +60,7 @@
}],
"outputs": []
}, {
- "name":"received",
+ "name":"Changed",
"type":"event",
"inputs": [
{"name":"from","type":"address","indexed":true},
@@ -69,18 +71,14 @@
var address = localStorage.getItem("address");
// deploy if not exist
if (address == null) {
- var code = "0x60056013565b61012b806100346000396000f35b6103e8600033600160a060020a0316600052602052604060002081905550560060e060020a6000350480637bb98a681461002b578063d0679d3414610039578063e3d670d71461004d57005b610033610126565b60006000f35b610047600435602435610062565b60006000f35b610058600435610104565b8060005260206000f35b80600033600160a060020a0316600052602052604060002054101561008657610100565b80600033600160a060020a0316600052602052604060002090815403908190555080600083600160a060020a0316600052602052604060002090815401908190555033600160a060020a0316600052806020527ff11e547d796cc64acdf758e7cee90439494fd886a19159454aa61e473fdbafef60406000a15b5050565b6000600082600160a060020a03166000526020526040600020549050919050565b5b60008156";
+ var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
address = web3.eth.transact({data: code});
localStorage.setItem("address", address);
}
- document.querySelector("#contract_addr").innerHTML = address.toUpperCase();
+ document.querySelector("#contract_addr").innerHTML = address;
var contract = web3.eth.contract(address, desc);
- contract.received({from: eth.coinbase}).changed(function() {
- refresh();
- });
-
- eth.watch('chain').changed(function() {
+ contract.Changed({from: eth.coinbase}).changed(function() {
refresh();
});
@@ -93,21 +91,33 @@
var storage = eth.storageAt(address);
table.innerHTML = "";
for( var item in storage ) {
- table.innerHTML += ""+item.toUpperCase()+" "+web3.toDecimal(storage[item])+" ";
+ table.innerHTML += ""+item+" "+web3.toDecimal(storage[item])+" ";
}
}
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 );
+ 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();
@@ -121,7 +131,7 @@ contract JevCoin {
balances[msg.sender] = 1000000;
}
- event changed(address indexed from, address indexed to);
+ event Changed(address indexed from, uint indexed amount);
function send(address to, uint value)
{
if( balances[msg.sender] < value ) return;
@@ -129,7 +139,8 @@ contract JevCoin {
balances[msg.sender] -= value;
balances[to] += value;
- changed(msg.sender, to);
+ Changed(msg.sender, value);
+ Changed(to, value);
}
function balance(address who) constant returns(uint t)
diff --git a/cmd/mist/assets/examples/info.html b/cmd/mist/assets/examples/info.html
index 2a405c280a..3b958a4945 100644
--- a/cmd/mist/assets/examples/info.html
+++ b/cmd/mist/assets/examples/info.html
@@ -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;
@@ -72,8 +74,9 @@
document.querySelector("#mining").innerHTML = eth.mining;
document.querySelector("#listening").innerHTML = eth.listening;
eth.watch('chain').changed(function() {
- document.querySelector("#number").innerHTML = eth.number;
- });
+ document.querySelector("#number").innerHTML = eth.number;
+ });
+
diff --git a/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js b/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
index 83b598b3f1..522b77ebfd 100644
--- a/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
+++ b/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
@@ -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 .
+*/
+/** @file db.js
+ * @authors:
+ * Marek Kotewicz
+ * @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 .
+*/
+/** @file eth.js
+ * @authors:
+ * Marek Kotewicz
+ * @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,84 +777,96 @@ 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
+/// 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;
+ }
+
+ options = options || {};
+
+ if (options.topics) {
+ console.warn('"topics" is deprecated, is "topic" instead');
+ }
+
+ // evaluate lazy properties
+ return {
+ to: options.to,
+ topic: options.topic,
+ earliest: options.earliest,
+ latest: options.latest,
+ max: options.max,
+ 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
-/// 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._onWatchResult = options._onWatchEventResult;
-
- // evaluate lazy properties
- options = {
- to: options.to,
- topic: options.topic,
- earliest: options.earliest,
- latest: options.latest,
- max: options.max,
- skip: options.skip,
- address: options.address
- };
-
+/// @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;
}
+
+ 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);
+ });
+ });
+ };
+
+ implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);
+
+ var changed = function (callback) {
+ callbacks.push(callback);
+ };
+
+ var messages = function () {
+ return implementation.getMessages(filterId);
+ };
- this.impl = impl;
- this.callbacks = [];
+ var uninstall = function () {
+ implementation.stopPolling(filterId);
+ implementation.uninstallFilter(filterId);
+ callbacks = [];
+ };
- this.id = impl.newFilter(options);
- web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));
+ return {
+ changed: changed,
+ arrived: changed,
+ happened: changed,
+ messages: messages,
+ logs: messages,
+ uninstall: uninstall
+ };
};
-/// alias for changed*
-Filter.prototype.arrived = function(callback) {
- this.changed(callback);
-};
-Filter.prototype.happened = function(callback) {
- this.changed(callback);
-};
+module.exports = filter;
-/// gets called when there is new eth/shh message
-Filter.prototype.changed = function(callback) {
- this.callbacks.push(callback);
-};
-/// 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);
- }
- }
-};
-
-/// should be called to uninstall current filter
-Filter.prototype.uninstall = function() {
- this.impl.uninstallFilter(this.id);
- web3.provider.stopPolling(this.id);
-};
-
-/// should be called to manually trigger getting latest messages from the client
-Filter.prototype.messages = function() {
- return this.impl.getMessages(this.id);
-};
-
-/// 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.
@@ -918,20 +1058,22 @@ var HttpSyncProvider = function (host) {
HttpSyncProvider.prototype.send = function (payload) {
//var data = formatJsonRpcObject(payload);
-
+
var request = new XMLHttpRequest();
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 .
-*/
-/** @file providermanager.js
- * @authors:
- * Jeffrey Wilcke
- * Marek Kotewicz
- * Marian Oancea
- * Gav Wood
- * @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 .
+*/
+/** @file requestmanager.js
+ * @authors:
+ * Jeffrey Wilcke
+ * Marek Kotewicz
+ * Marian Oancea
+ * Gav Wood
+ * @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 .
+*/
+/** @file shh.js
+ * @authors:
+ * Marek Kotewicz
+ * @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 .
+*/
+/** @file watches.js
+ * @authors:
+ * Marek Kotewicz
+ * @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
diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml
index ca37dbf3c3..a909916b7e 100644
--- a/cmd/mist/assets/qml/main.qml
+++ b/cmd/mist/assets/qml/main.qml
@@ -964,7 +964,7 @@ ApplicationWindow {
anchors.top: parent.top
anchors.topMargin: 30
font.pointSize: 12
- text: "Mist (0.8.4) Development Jeffrey Wilcke Viktor Trón Felix Lange Taylor Gerring Daniel Nagy Gustav SimonssonUX/UI Alex van de Sande Fabian Vogelsteller"
+ text: "Mist (0.8.6) Development Jeffrey Wilcke Viktor Trón Felix Lange Taylor Gerring Daniel Nagy Gustav SimonssonUX/UI Alex van de Sande Fabian Vogelsteller"
}
}
diff --git a/cmd/mist/flags.go b/cmd/mist/flags.go
index d9487de9e0..0010df8265 100644
--- a/cmd/mist/flags.go
+++ b/cmd/mist/flags.go
@@ -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"
@@ -68,38 +66,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
@@ -121,12 +88,12 @@ func Init() {
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(&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 (
diff --git a/cmd/mist/main.go b/cmd/mist/main.go
index 45eddeb283..3abe167671 100644
--- a/cmd/mist/main.go
+++ b/cmd/mist/main.go
@@ -36,7 +36,7 @@ import (
const (
ClientIdentifier = "Mist"
- Version = "0.8.4"
+ Version = "0.8.6"
)
var ethereum *eth.Ethereum
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index d252f3ab24..a36c10e3bf 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -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"
@@ -132,31 +128,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
@@ -272,7 +243,7 @@ func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
parent := ethereum.ChainManager().GetBlock(block.ParentHash())
statedb := state.New(parent.Root(), ethereum.Db())
- _, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block)
+ _, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block, true)
if err != nil {
return err
}
diff --git a/core/block_processor.go b/core/block_processor.go
index bfd9d45608..7eaeb5be09 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -48,9 +48,8 @@ type BlockProcessor struct {
func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
sm := &BlockProcessor{
- db: db,
- mem: make(map[string]*big.Int),
- //Pow: ðash.Ethash{},
+ db: db,
+ mem: make(map[string]*big.Int),
Pow: ezp.New(),
bc: chainManager,
eventMux: eventMux,
@@ -60,12 +59,12 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
return sm
}
-func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) {
+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(), false)
+ receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
if err != nil {
return nil, err
}
@@ -100,10 +99,10 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
// Notify all subscribers
if !transientProcess {
go self.eventMux.Post(TxPostEvent{tx})
+ logs := statedb.Logs()
+ go self.eventMux.Post(logs)
}
- go self.eventMux.Post(statedb.Logs())
-
return receipt, txGas, err
}
@@ -179,7 +178,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
return
}
- receipts, err := sm.TransitionState(state, parent, block)
+ receipts, err := sm.TransitionState(state, parent, block, false)
if err != nil {
return
}
@@ -248,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)
}
@@ -316,13 +320,10 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
var (
parent = sm.bc.GetBlock(block.Header().ParentHash)
- //state = state.New(parent.Trie().Copy())
- state = state.New(parent.Root(), sm.db)
+ state = state.New(parent.Root(), sm.db)
)
- defer state.Reset()
-
- sm.TransitionState(state, parent, block)
+ sm.TransitionState(state, parent, block, true)
sm.AccumulateRewards(state, block, parent)
return state.Logs(), nil
diff --git a/core/chain_makers.go b/core/chain_makers.go
new file mode 100644
index 0000000000..eb43f8aa08
--- /dev/null
+++ b/core/chain_makers.go
@@ -0,0 +1,131 @@
+package core
+
+import (
+ "fmt"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/pow"
+ "github.com/ethereum/go-ethereum/state"
+ "math/big"
+)
+
+// So we can generate blocks easily
+type FakePow struct{}
+
+func (f FakePow) Search(block pow.Block, stop <-chan struct{}) []byte { return nil }
+func (f FakePow) Verify(block pow.Block) bool { return true }
+func (f FakePow) GetHashrate() int64 { return 0 }
+func (f FakePow) Turbo(bool) {}
+
+func NewBlockFromParent(addr []byte, parent *types.Block) *types.Block {
+ return newBlockFromParent(addr, parent)
+}
+
+func MakeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database) *types.Block {
+ return makeBlock(bman, parent, i, db)
+}
+
+func MakeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database) types.Blocks {
+ return makeChain(bman, parent, max, db)
+}
+
+func NewChainMan(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager {
+ return newChainManager(block, eventMux, db)
+}
+
+func NewBlockProc(db ethutil.Database, txpool *TxPool, cman *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+ return newBlockProcessor(db, txpool, cman, eventMux)
+}
+
+func NewCanonical(n int, db ethutil.Database) (*BlockProcessor, error) {
+ return newCanonical(n, db)
+}
+
+func newBlockFromParent(addr []byte, parent *types.Block) *types.Block {
+ block := types.NewBlock(parent.Hash(), addr, parent.Root(), ethutil.BigPow(2, 32), nil, "")
+
+ block.SetUncles(nil)
+ block.SetTransactions(nil)
+ block.SetReceipts(nil)
+
+ header := block.Header()
+ header.Difficulty = CalcDifficulty(block, parent)
+ header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
+ header.GasLimit = CalcGasLimit(parent, block)
+
+ block.Td = parent.Td
+
+ return block
+}
+
+// Actually make a block by simulating what miner would do
+func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database) *types.Block {
+ addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20)
+ block := newBlockFromParent(addr, parent)
+ state := state.New(block.Root(), db)
+ cbase := state.GetOrNewStateObject(addr)
+ cbase.SetGasPool(CalcGasLimit(parent, block))
+ cbase.AddBalance(BlockReward)
+ state.Update(ethutil.Big0)
+ block.SetRoot(state.Root())
+ return block
+}
+
+// Make a chain with real blocks
+// Runs ProcessWithParent to get proper state roots
+func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database) types.Blocks {
+ bman.bc.currentBlock = parent
+ blocks := make(types.Blocks, max)
+ for i := 0; i < max; i++ {
+ block := makeBlock(bman, parent, i, db)
+ td, err := bman.processWithParent(block, parent)
+ if err != nil {
+ fmt.Println("process with parent failed", err)
+ panic(err)
+ }
+ block.Td = td
+ blocks[i] = block
+ parent = block
+ fmt.Printf("New Block: %x\n", block.Hash())
+ }
+ fmt.Println("Done making chain")
+ return blocks
+}
+
+// Create a new chain manager starting from given block
+// Effectively a fork factory
+func newChainManager(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager {
+ bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
+ if block == nil {
+ bc.Reset()
+ } else {
+ bc.currentBlock = block
+ bc.td = block.Td
+ }
+ return bc
+}
+
+// block processor with fake pow
+func newBlockProcessor(db ethutil.Database, txpool *TxPool, cman *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+ bman := NewBlockProcessor(db, txpool, newChainManager(nil, eventMux, db), eventMux)
+ bman.Pow = FakePow{}
+ return bman
+}
+
+// Make a new canonical chain by running InsertChain
+// on result of makeChain
+func newCanonical(n int, db ethutil.Database) (*BlockProcessor, error) {
+ eventMux := &event.TypeMux{}
+ txpool := NewTxPool(eventMux)
+
+ bman := newBlockProcessor(db, txpool, newChainManager(nil, eventMux, db), eventMux)
+ bman.bc.SetProcessor(bman)
+ parent := bman.bc.CurrentBlock()
+ if n == 0 {
+ return bman, nil
+ }
+ lchain := makeChain(bman, parent, n, db)
+ bman.bc.InsertChain(lchain)
+ return bman, nil
+}
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 9ef091c3cf..959bfd3986 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -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})
}
}
diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
index bc3a264d1e..b76ac187c0 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -3,6 +3,7 @@ package core
import (
"bytes"
"fmt"
+ "math/big"
"os"
"path"
"runtime"
@@ -13,7 +14,9 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/state"
)
func init() {
@@ -21,6 +24,61 @@ func init() {
ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
}
+// Test fork of length N starting from block i
+func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) {
+ fmt.Println("Testing Fork!")
+ var b *types.Block = nil
+ if i > 0 {
+ b = bman.bc.GetBlockByNumber(uint64(i))
+ }
+ _ = b
+ // switch databases to process the new chain
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ // copy old chain up to i into new db with deterministic canonical
+ bman2, err := newCanonical(i, db)
+ if err != nil {
+ t.Fatal("could not make new canonical in testFork", err)
+ }
+ bman2.bc.SetProcessor(bman2)
+
+ parent := bman2.bc.CurrentBlock()
+ chainB := makeChain(bman2, parent, N, db)
+ bman2.bc.InsertChain(chainB)
+
+ tdpre := bman.bc.Td()
+ td, err := testChain(chainB, bman)
+ if err != nil {
+ t.Fatal("expected chainB not to give errors:", err)
+ }
+ // Compare difficulties
+ f(tdpre, td)
+}
+
+func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
+ td := new(big.Int)
+ for _, block := range chainB {
+ td2, err := bman.bc.processor.Process(block)
+ if err != nil {
+ if IsKnownBlockErr(err) {
+ continue
+ }
+ return nil, err
+ }
+ block.Td = td2
+ td = td2
+
+ bman.bc.mu.Lock()
+ {
+ bman.bc.write(block)
+ }
+ bman.bc.mu.Unlock()
+ }
+ return td, nil
+}
+
func loadChain(fn string, t *testing.T) (types.Blocks, error) {
fh, err := os.OpenFile(path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm)
if err != nil {
@@ -45,6 +103,128 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *
done <- true
}
+func TestExtendCanonical(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ // make first chain starting from genesis
+ bman, err := newCanonical(5, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ f := func(td1, td2 *big.Int) {
+ if td2.Cmp(td1) <= 0 {
+ t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
+ }
+ }
+ // Start fork from current height (5)
+ testFork(t, bman, 5, 1, f)
+ testFork(t, bman, 5, 2, f)
+ testFork(t, bman, 5, 5, f)
+ testFork(t, bman, 5, 10, f)
+}
+
+func TestShorterFork(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ // make first chain starting from genesis
+ bman, err := newCanonical(10, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ f := func(td1, td2 *big.Int) {
+ if td2.Cmp(td1) >= 0 {
+ t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1)
+ }
+ }
+ // Sum of numbers must be less than 10
+ // for this to be a shorter fork
+ testFork(t, bman, 0, 3, f)
+ testFork(t, bman, 0, 7, f)
+ testFork(t, bman, 1, 1, f)
+ testFork(t, bman, 1, 7, f)
+ testFork(t, bman, 5, 3, f)
+ testFork(t, bman, 5, 4, f)
+}
+
+func TestLongerFork(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ // make first chain starting from genesis
+ bman, err := newCanonical(10, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ f := func(td1, td2 *big.Int) {
+ if td2.Cmp(td1) <= 0 {
+ t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
+ }
+ }
+ // Sum of numbers must be greater than 10
+ // for this to be a longer fork
+ testFork(t, bman, 0, 11, f)
+ testFork(t, bman, 0, 15, f)
+ testFork(t, bman, 1, 10, f)
+ testFork(t, bman, 1, 12, f)
+ testFork(t, bman, 5, 6, f)
+ testFork(t, bman, 5, 8, f)
+}
+
+func TestEqualFork(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ bman, err := newCanonical(10, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ f := func(td1, td2 *big.Int) {
+ if td2.Cmp(td1) != 0 {
+ t.Error("expected chainB to have equal difficulty. Got", td2, "expected ", td1)
+ }
+ }
+ // Sum of numbers must be equal to 10
+ // for this to be an equal fork
+ testFork(t, bman, 1, 9, f)
+ testFork(t, bman, 2, 8, f)
+ testFork(t, bman, 5, 5, f)
+ testFork(t, bman, 6, 4, f)
+ testFork(t, bman, 9, 1, f)
+}
+
+func TestBrokenChain(t *testing.T) {
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ bman, err := newCanonical(10, db)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ db2, err := ethdb.NewMemDatabase()
+ if err != nil {
+ t.Fatal("Failed to create db:", err)
+ }
+ bman2, err := newCanonical(10, db2)
+ if err != nil {
+ t.Fatal("Could not make new canonical chain:", err)
+ }
+ bman2.bc.SetProcessor(bman2)
+ parent := bman2.bc.CurrentBlock()
+ chainB := makeChain(bman2, parent, 5, db2)
+ chainB = chainB[1:]
+ _, err = testChain(chainB, bman)
+ if err == nil {
+ t.Error("expected broken chain to return error")
+ }
+}
+
func TestChainInsertions(t *testing.T) {
t.Skip() // travil fails.
diff --git a/core/filter.go b/core/filter.go
index 88f12a67c0..cdf7b282d3 100644
--- a/core/filter.go
+++ b/core/filter.go
@@ -111,14 +111,14 @@ func (self *Filter) Find() state.Logs {
// current parameters
if self.bloomFilter(block) {
// Get the logs of the block
- logs, err := self.eth.BlockProcessor().GetLogs(block)
+ unfiltered, err := self.eth.BlockProcessor().GetLogs(block)
if err != nil {
chainlogger.Warnln("err: filter get logs ", err)
break
}
- logs = append(logs, self.FilterLogs(logs)...)
+ logs = append(logs, self.FilterLogs(unfiltered)...)
}
block = self.eth.ChainManager().GetBlock(block.ParentHash())
@@ -146,7 +146,6 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
Logs:
for _, log := range logs {
if !includes(self.address, log.Address()) {
- //if !bytes.Equal(self.address, log.Address()) {
continue
}
diff --git a/core/state_transition.go b/core/state_transition.go
index 36ffa23d9f..7331fdd4a5 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -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() {
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index 050cff3d8a..860f57dc30 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -117,8 +117,13 @@ func (self *TxPool) add(tx *types.Transaction) error {
} else {
to = "[NEW_CONTRACT]"
}
-
- txplogger.Debugf("(t) %x => %s (%v) %x\n", tx.From()[:4], to, tx.Value, tx.Hash())
+ var from string
+ if len(tx.From()) > 0 {
+ from = ethutil.Bytes2Hex(tx.From()[:4])
+ } else {
+ from = "INVALID"
+ }
+ txplogger.Debugf("(t) %x => %s (%v) %x\n", from, to, tx.Value, tx.Hash())
// Notify the subscribers
go self.eventMux.Post(TxPreEvent{tx})
diff --git a/crypto/key_store_plain.go b/crypto/key_store_plain.go
index 6b76962a0b..338a4a2c34 100644
--- a/crypto/key_store_plain.go
+++ b/crypto/key_store_plain.go
@@ -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
}
diff --git a/crypto/key_store_test.go b/crypto/key_store_test.go
index 485d8f5367..11531d4601 100644
--- a/crypto/key_store_test.go
+++ b/crypto/key_store_test.go
@@ -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 {
diff --git a/eth/backend.go b/eth/backend.go
index b57e9fd69e..f67f9c78b0 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -3,6 +3,8 @@ package eth
import (
"crypto/ecdsa"
"fmt"
+ "io/ioutil"
+ "path"
"strings"
"github.com/ethereum/go-ethereum/core"
@@ -25,7 +27,10 @@ var (
jsonlogger = ethlogger.NewJsonLogger()
defaultBootNodes = []*discover.Node{
+ // ETH/DEV cmd/bootnode
discover.MustParseNode("enode://6cdd090303f394a1cac34ecc9f7cda18127eafa2a3a06de39f6d920b0e583e062a7362097c7c65ee490a758b442acd5c80c6fce4b148c6a391e946b45131365b@54.169.166.226:30303"),
+ // ETH/DEV cpp-ethereum (poc-8.ethdev.com)
+ discover.MustParseNode("enode://4a44599974518ea5b0f14c31c4463692ac0329cb84851f3435e6d1b18ee4eae4aa495f846a0fa1219bd58035671881d44423876e57db2abd57254d0197da0ebe@5.1.83.226:30303"),
}
)
@@ -77,6 +82,27 @@ func (cfg *Config) parseBootNodes() []*discover.Node {
return ns
}
+func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
+ // use explicit key from command line args if set
+ if cfg.NodeKey != nil {
+ return cfg.NodeKey, nil
+ }
+ // use persistent key if present
+ keyfile := path.Join(cfg.DataDir, "nodekey")
+ key, err := crypto.LoadECDSA(keyfile)
+ if err == nil {
+ return key, nil
+ }
+ // no persistent key, generate and store a new one
+ if key, err = crypto.GenerateKey(); err != nil {
+ 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)
+ }
+ return key, nil
+}
+
type Ethereum struct {
// Channel for shutting down the ethereum
shutdownChan chan bool
@@ -121,7 +147,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, "database")
+ return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, path)
}
// Create new keymanager
@@ -161,18 +188,16 @@ func New(config *Config) (*Ethereum, error) {
insertChain := eth.chainManager.InsertChain
eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify)
+ netprv, err := config.nodeKey()
+ if err != nil {
+ return nil, err
+ }
ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
protocols := []p2p.Protocol{ethProto}
if config.Shh {
protocols = append(protocols, eth.whisper.Protocol())
}
- netprv := config.NodeKey
- if netprv == nil {
- if netprv, err = crypto.GenerateKey(); err != nil {
- return nil, fmt.Errorf("could not generate server key: %v", err)
- }
- }
eth.net = &p2p.Server{
PrivateKey: netprv,
Name: config.Name,
diff --git a/ethutil/common.go b/ethutil/common.go
index 2ef2440c78..c4e7415dc1 100644
--- a/ethutil/common.go
+++ b/ethutil/common.go
@@ -3,10 +3,51 @@ package ethutil
import (
"fmt"
"math/big"
+ "os"
+ "os/user"
+ "path"
+ "path/filepath"
"runtime"
"time"
+
+ "github.com/kardianos/osext"
)
+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()
+ 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"
}
diff --git a/event/filter/eth_filter.go b/event/filter/eth_filter.go
index 73d2cd9358..4ba66a7e07 100644
--- a/event/filter/eth_filter.go
+++ b/event/filter/eth_filter.go
@@ -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()
diff --git a/gocoverage.sh b/gocoverage.sh
index e54a5cab03..5479d8d3b7 100755
--- a/gocoverage.sh
+++ b/gocoverage.sh
@@ -29,6 +29,3 @@ if ls $dir/*.go &> /dev/null; then
fi
fi
done
-
-go tool cover -func profile.cov
-
diff --git a/miner/worker.go b/miner/worker.go
index 1f3a52ab52..4f0909302c 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -197,7 +197,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 +225,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)
diff --git a/rpc/packages.go b/rpc/api.go
similarity index 71%
rename from rpc/packages.go
rename to rpc/api.go
index aed43cae2b..28024c2062 100644
--- a/rpc/packages.go
+++ b/rpc/api.go
@@ -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,
- quit: make(chan struct{}),
- filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
- logs: make(map[int]*logFilter),
- messages: make(map[int]*whisperFilter),
- db: db,
+ 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
@@ -167,42 +232,64 @@ func (self *EthereumApi) Logs(id int, reply *interface{}) error {
return nil
}
-func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
- err := args.requirements()
- if err != nil {
- return err
- }
+func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error {
+ filter := core.NewFilter(self.xeth().Backend())
+ filter.SetOptions(toFilterOptions(args))
- if args.BlockNumber > 0 {
- *reply = p.xeth.BlockByNumber(args.BlockNumber)
+ *reply = toLogs(filter.Find())
+
+ return nil
+}
+
+func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
+ // 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
}
@@ -216,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
}
@@ -227,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
@@ -249,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
}
@@ -293,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
}
@@ -302,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
}
@@ -312,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
}
@@ -359,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
}
@@ -368,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
}
@@ -390,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
}
@@ -400,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":
@@ -425,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":
@@ -509,8 +615,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
return err
}
return p.Logs(args, reply)
+ case "eth_logs":
+ args, err := req.ToFilterArgs()
+ if err != nil {
+ return err
+ }
+ return p.AllLogs(args, reply)
case "eth_gasPrice":
- *reply = defaultGasPrice
+ *reply = toHex(defaultGasPrice.Bytes())
return nil
case "eth_register":
args, err := req.ToRegisterArgs()
@@ -589,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 t(f ui.Frontend) {
+ // Call the password dialog
+ ret, err := f.Call("PasswordDialog")
+ if err != nil {
+ fmt.Println(err)
}
-}
-
-func (self *EthereumApi) stop() {
- close(self.quit)
+ // Get the first argument
+ t, _ := ret.Get(0)
+ fmt.Println("return:", t)
}
diff --git a/rpc/packages_test.go b/rpc/api_test.go
similarity index 98%
rename from rpc/packages_test.go
rename to rpc/api_test.go
index 037fd78b39..a9fc16cd37 100644
--- a/rpc/packages_test.go
+++ b/rpc/api_test.go
@@ -7,6 +7,7 @@ import (
)
func TestFilterClose(t *testing.T) {
+ t.Skip()
api := &EthereumApi{
logs: make(map[int]*logFilter),
messages: make(map[int]*whisperFilter),
diff --git a/rpc/args.go b/rpc/args.go
index f730819fd9..e839da8bf9 100644
--- a/rpc/args.go
+++ b/rpc/args.go
@@ -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
}
@@ -277,10 +240,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
}
diff --git a/rpc/http/server.go b/rpc/http/server.go
index dd6ba68e32..fa66eed487 100644
--- a/rpc/http/server.go
+++ b/rpc/http/server.go
@@ -92,7 +92,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
}
diff --git a/rpc/message.go b/rpc/messages.go
similarity index 64%
rename from rpc/message.go
rename to rpc/messages.go
index 825ede05b7..b37d8229d6 100644
--- a/rpc/message.go
+++ b/rpc/messages.go
@@ -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
}
diff --git a/rpc/util.go b/rpc/util.go
index 29824bcdb9..3e8ca3fef0 100644
--- a/rpc/util.go
+++ b/rpc/util.go
@@ -82,8 +82,9 @@ 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"`
}
func toLogs(logs state.Logs) (ls []Log) {
@@ -94,6 +95,7 @@ func toLogs(logs state.Logs) (ls []Log) {
l.Topic = make([]string, len(log.Topics()))
l.Address = toHex(log.Address())
l.Data = toHex(log.Data())
+ l.Number = log.Number()
for j, topic := range log.Topics() {
l.Topic[j] = toHex(topic)
}
@@ -106,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) {
@@ -121,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) {
diff --git a/rpc/ws/server.go b/rpc/ws/server.go
index b8cc2fa6b2..2c2988f5d5 100644
--- a/rpc/ws/server.go
+++ b/rpc/ws/server.go
@@ -99,7 +99,7 @@ func sockHandler(api *rpc.EthereumApi) websocket.Handler {
// reqParsed, reqerr := JSON.ParseRequestBody(conn.Request())
if err := websocket.JSON.Receive(conn, &reqParsed); err != nil {
- jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest}
+ jsonerr := &rpc.RpcErrorObject{-32700, "Error: Could not parse request"}
JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
continue
}
diff --git a/state/dump.go b/state/dump.go
index 81895f1a37..073f89414a 100644
--- a/state/dump.go
+++ b/state/dump.go
@@ -35,7 +35,7 @@ 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
}
diff --git a/state/log.go b/state/log.go
index 46360f4aae..d503bd1a07 100644
--- a/state/log.go
+++ b/state/log.go
@@ -12,16 +12,19 @@ type Log interface {
Address() []byte
Topics() [][]byte
Data() []byte
+
+ Number() uint64
}
type StateLog struct {
address []byte
topics [][]byte
data []byte
+ number uint64
}
-func NewLog(address []byte, topics [][]byte, data []byte) *StateLog {
- return &StateLog{address, topics, data}
+func NewLog(address []byte, topics [][]byte, data []byte, number uint64) *StateLog {
+ return &StateLog{address, topics, data, number}
}
func (self *StateLog) Address() []byte {
@@ -36,6 +39,10 @@ func (self *StateLog) Data() []byte {
return self.data
}
+func (self *StateLog) Number() uint64 {
+ return self.number
+}
+
func NewLogFromValue(decoder *ethutil.Value) *StateLog {
log := &StateLog{
address: decoder.Get(0).Bytes(),
diff --git a/state/state_object.go b/state/state_object.go
index 477b912a12..487952a022 100644
--- a/state/state_object.go
+++ b/state/state_object.go
@@ -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
diff --git a/ui/frontend.go b/ui/frontend.go
new file mode 100644
index 0000000000..22dc64fdfd
--- /dev/null
+++ b/ui/frontend.go
@@ -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)
+}
diff --git a/vm/environment.go b/vm/environment.go
index 8507e248f8..5b4d6c8f0a 100644
--- a/vm/environment.go
+++ b/vm/environment.go
@@ -54,6 +54,7 @@ type Log struct {
address []byte
topics [][]byte
data []byte
+ log uint64
}
func (self *Log) Address() []byte {
@@ -68,6 +69,10 @@ func (self *Log) Data() []byte {
return self.data
}
+func (self *Log) Number() uint64 {
+ return self.log
+}
+
func (self *Log) RlpData() interface{} {
return []interface{}{self.address, ethutil.ByteSliceToInterface(self.topics), self.data}
}
diff --git a/vm/vm.go b/vm/vm.go
index 5ec507ddc6..7aeeea6619 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -578,7 +578,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
}
data := mem.Get(mStart.Int64(), mSize.Int64())
- log := &Log{context.Address(), topics, data}
+ log := &Log{context.Address(), topics, data, self.env.BlockNumber().Uint64()}
self.env.AddLog(log)
self.Printf(" => %v", log)
@@ -664,6 +664,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 +728,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
@@ -779,9 +780,9 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
// Stack Check, memory resize & gas phase
switch op {
// Stack checks only
- case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1
+ case ISZERO, CALLDATALOAD, POP, JUMP, NOT, EXTCODESIZE, BLOCKHASH: // 1
stack.require(1)
- case JUMPI, ADD, SUB, DIV, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
+ case JUMPI, ADD, SUB, DIV, MUL, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
stack.require(2)
case ADDMOD, MULMOD: // 3
stack.require(3)
@@ -828,7 +829,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 {
@@ -859,7 +860,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
additionalGas.Set(stack.data[stack.Len()-2])
case CALLDATACOPY:
- stack.require(2)
+ stack.require(3)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
additionalGas.Set(stack.data[stack.Len()-3])
diff --git a/whisper/whisper.go b/whisper/whisper.go
index 50c2f98fd2..13209f9a6e 100644
--- a/whisper/whisper.go
+++ b/whisper/whisper.go
@@ -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 {
diff --git a/xeth/world.go b/xeth/state.go
similarity index 63%
rename from xeth/world.go
rename to xeth/state.go
index 9cbdd9461e..e2562613cf 100644
--- a/xeth/world.go
+++ b/xeth/state.go
@@ -3,19 +3,20 @@ package xeth
import "github.com/ethereum/go-ethereum/state"
type State struct {
- xeth *XEth
+ 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())
}
diff --git a/xeth/xeth.go b/xeth/xeth.go
index f3569e4549..d4c188fec2 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -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) State() *State { return self.state }
+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())
}
@@ -288,13 +302,11 @@ func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string)
//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)
- */
+ // 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 {