Merge branch 'publictests' of github.com:ebuchman/go-ethereum into ethash_pow

This commit is contained in:
Matthew Wampler-Doty 2015-02-27 16:13:31 -05:00
commit 3820a65299
52 changed files with 1550 additions and 786 deletions

View File

@ -1,15 +1,20 @@
language: go language: go
go: go:
- 1.4.1 - 1.4.2
before_install: 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 update -qq
- sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine - sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine
install: install:
# - go get code.google.com/p/go.tools/cmd/goimports
# - go get github.com/golang/lint/golint
# - go get golang.org/x/tools/cmd/vet # - go get golang.org/x/tools/cmd/vet
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi - 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 - go get github.com/mattn/goveralls
before_script: before_script:
# - gofmt -l -w .
# - goimports -l -w .
# - golint .
# - go vet ./... # - go vet ./...
# - go test -race ./... # - go test -race ./...
script: script:

11
Godeps/Godeps.json generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,16 +5,16 @@
package osext package osext
import ( import (
"syscall" "os"
"os" "strconv"
"strconv" "syscall"
) )
func executable() (string, error) { func executable() (string, error) {
f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
if err != nil { if err != nil {
return "", err return "", err
} }
defer f.Close() defer f.Close()
return syscall.Fd2path(int(f.Fd())) return syscall.Fd2path(int(f.Fd()))
} }

View File

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

View File

@ -34,33 +34,62 @@ package accounts
import ( import (
crand "crypto/rand" crand "crypto/rand"
"errors"
"sync"
"time"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
) )
var ErrLocked = errors.New("account is locked; please request passphrase")
// TODO: better name for this struct? // TODO: better name for this struct?
type Account struct { type Account struct {
Address []byte Address []byte
} }
type AccountManager struct { 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 func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Duration) AccountManager {
keysMap := make(map[string]crypto.Key)
// TODO: pass through passphrase for APIs which require access to private key?
func NewAccountManager(keyStore crypto.KeyStore2) AccountManager {
am := &AccountManager{ am := &AccountManager{
keyStore: keyStore, keyStore: keyStore,
unlockedKeys: keysMap,
unlockMilliseconds: unlockMilliseconds,
} }
return *am 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) key, err := am.keyStore.GetKey(fromAccount.Address, keyAuth)
if err != nil { if err != nil {
return nil, err 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) signature, err = crypto.Sign(toSign, key.PrivateKey)
return signature, err return signature, err
} }
@ -76,8 +105,6 @@ func (am AccountManager) NewAccount(auth string) (*Account, error) {
return ua, err 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) { func (am *AccountManager) Accounts() ([]Account, error) {
addresses, err := am.keyStore.GetKeyAddresses() addresses, err := am.keyStore.GetKeyAddresses()
if err != nil { if err != nil {
@ -93,3 +120,13 @@ func (am *AccountManager) Accounts() ([]Account, error) {
} }
return accounts, err return accounts, err
} }
func unlockLater(am *AccountManager, addr []byte) {
select {
case <-time.After(time.Millisecond * am.unlockMilliseconds):
}
am.mutex.RLock()
// TODO: how do we know the key is actually gone from memory?
delete(am.unlockedKeys, string(addr))
am.mutex.RUnlock()
}

View File

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

View File

@ -26,10 +26,10 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"os/user"
"path" "path"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/vm" "github.com/ethereum/go-ethereum/vm"
@ -79,12 +79,7 @@ var (
InputFile string InputFile string
) )
func defaultDataDir() string { var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini")
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereum")
}
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
func Init() { func Init() {
// TODO: move common flag processing to cmd/util // 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(&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(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") 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(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")

View File

@ -37,7 +37,7 @@ import (
const ( const (
ClientIdentifier = "Ethereum(G)" ClientIdentifier = "Ethereum(G)"
Version = "0.8.4" Version = "0.8.6"
) )
var clilogger = logger.NewLogger("CLI") var clilogger = logger.NewLogger("CLI")

View File

@ -14,10 +14,12 @@
</div> </div>
<div> <div>
<span class="amount">Amount:</span> <span>Address:</span>
<input type="text" id="address" style="width:200px"> <input type="text" id="address" style="width:200px">
<span>Amount:</span>
<input type="text" id="amount" style="width:200px"> <input type="text" id="amount" style="width:200px">
<button onclick="transact()">Send</button> <button onclick="transact()">Send</button>
<span id="message"></span>
</div> </div>
<hr> <hr>
@ -58,7 +60,7 @@
}], }],
"outputs": [] "outputs": []
}, { }, {
"name":"received", "name":"Changed",
"type":"event", "type":"event",
"inputs": [ "inputs": [
{"name":"from","type":"address","indexed":true}, {"name":"from","type":"address","indexed":true},
@ -69,18 +71,14 @@
var address = localStorage.getItem("address"); var address = localStorage.getItem("address");
// deploy if not exist // deploy if not exist
if (address == null) { if (address == null) {
var code = "0x60056013565b61012b806100346000396000f35b6103e8600033600160a060020a0316600052602052604060002081905550560060e060020a6000350480637bb98a681461002b578063d0679d3414610039578063e3d670d71461004d57005b610033610126565b60006000f35b610047600435602435610062565b60006000f35b610058600435610104565b8060005260206000f35b80600033600160a060020a0316600052602052604060002054101561008657610100565b80600033600160a060020a0316600052602052604060002090815403908190555080600083600160a060020a0316600052602052604060002090815401908190555033600160a060020a0316600052806020527ff11e547d796cc64acdf758e7cee90439494fd886a19159454aa61e473fdbafef60406000a15b5050565b6000600082600160a060020a03166000526020526040600020549050919050565b5b60008156"; var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
address = web3.eth.transact({data: code}); address = web3.eth.transact({data: code});
localStorage.setItem("address", address); localStorage.setItem("address", address);
} }
document.querySelector("#contract_addr").innerHTML = address.toUpperCase(); document.querySelector("#contract_addr").innerHTML = address;
var contract = web3.eth.contract(address, desc); var contract = web3.eth.contract(address, desc);
contract.received({from: eth.coinbase}).changed(function() { contract.Changed({from: eth.coinbase}).changed(function() {
refresh();
});
eth.watch('chain').changed(function() {
refresh(); refresh();
}); });
@ -93,21 +91,33 @@
var storage = eth.storageAt(address); var storage = eth.storageAt(address);
table.innerHTML = ""; table.innerHTML = "";
for( var item in storage ) { for( var item in storage ) {
table.innerHTML += "<tr><td>"+item.toUpperCase()+"</td><td>"+web3.toDecimal(storage[item])+"</td></tr>"; table.innerHTML += "<tr><td>"+item+"</td><td>"+web3.toDecimal(storage[item])+"</td></tr>";
} }
} }
function transact() { function transact() {
var to = document.querySelector("#address").value; var to = document.querySelector("#address");
if( to.length == 0 ) { if( to.value.length == 0 ) {
to = "0x4205b06c2cfa0e30359edcab94543266cb6fa1d3"; to = "0x4205b06c2cfa0e30359edcab94543266cb6fa1d3";
} else { } 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(); refresh();
@ -121,7 +131,7 @@ contract JevCoin {
balances[msg.sender] = 1000000; 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) function send(address to, uint value)
{ {
if( balances[msg.sender] < value ) return; if( balances[msg.sender] < value ) return;
@ -129,7 +139,8 @@ contract JevCoin {
balances[msg.sender] -= value; balances[msg.sender] -= value;
balances[to] += value; balances[to] += value;
changed(msg.sender, to); Changed(msg.sender, value);
Changed(to, value);
} }
function balance(address who) constant returns(uint t) function balance(address who) constant returns(uint t)

View File

@ -62,6 +62,8 @@
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545')); web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545'));
eth.defaultBlock = -2
document.querySelector("#number").innerHTML = eth.number; document.querySelector("#number").innerHTML = eth.number;
document.querySelector("#coinbase").innerHTML = eth.coinbase document.querySelector("#coinbase").innerHTML = eth.coinbase
document.querySelector("#peer_count").innerHTML = eth.peerCount; document.querySelector("#peer_count").innerHTML = eth.peerCount;
@ -72,8 +74,9 @@
document.querySelector("#mining").innerHTML = eth.mining; document.querySelector("#mining").innerHTML = eth.mining;
document.querySelector("#listening").innerHTML = eth.listening; document.querySelector("#listening").innerHTML = eth.listening;
eth.watch('chain').changed(function() { eth.watch('chain').changed(function() {
document.querySelector("#number").innerHTML = eth.number; document.querySelector("#number").innerHTML = eth.number;
}); });
</script> </script>

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -26,13 +26,11 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"os/user"
"path" "path"
"path/filepath"
"runtime" "runtime"
"bitbucket.org/kardianos/osext"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/vm" "github.com/ethereum/go-ethereum/vm"
@ -68,38 +66,7 @@ var (
// flags specific to gui client // flags specific to gui client
var AssetPath string var AssetPath string
var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini")
//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")
func Init() { func Init() {
// TODO: move common flag processing to cmd/utils // 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(&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(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") 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(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory") flag.StringVar(&AssetPath, "asset_path", ethutil.DefaultAssetPath(), "absolute path to GUI assets directory")
// Network stuff // Network stuff
var ( var (

View File

@ -36,7 +36,7 @@ import (
const ( const (
ClientIdentifier = "Mist" ClientIdentifier = "Mist"
Version = "0.8.4" Version = "0.8.6"
) )
var ethereum *eth.Ethereum var ethereum *eth.Ethereum

View File

@ -25,12 +25,8 @@ import (
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"path"
"path/filepath"
"regexp" "regexp"
"runtime"
"bitbucket.org/kardianos/osext"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth" "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) { func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
var err error var err error
@ -272,7 +243,7 @@ func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
parent := ethereum.ChainManager().GetBlock(block.ParentHash()) parent := ethereum.ChainManager().GetBlock(block.ParentHash())
statedb := state.New(parent.Root(), ethereum.Db()) 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 { if err != nil {
return err return err
} }

View File

@ -48,9 +48,8 @@ type BlockProcessor struct {
func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor { func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
sm := &BlockProcessor{ sm := &BlockProcessor{
db: db, db: db,
mem: make(map[string]*big.Int), mem: make(map[string]*big.Int),
//Pow: &ethash.Ethash{},
Pow: ezp.New(), Pow: ezp.New(),
bc: chainManager, bc: chainManager,
eventMux: eventMux, eventMux: eventMux,
@ -60,12 +59,12 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
return sm 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 := statedb.GetOrNewStateObject(block.Header().Coinbase)
coinbase.SetGasPool(CalcGasLimit(parent, block)) coinbase.SetGasPool(block.Header().GasLimit)
// Process the transactions on to parent state // 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 { if err != nil {
return nil, err return nil, err
} }
@ -100,10 +99,10 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
// Notify all subscribers // Notify all subscribers
if !transientProcess { if !transientProcess {
go self.eventMux.Post(TxPostEvent{tx}) go self.eventMux.Post(TxPostEvent{tx})
logs := statedb.Logs()
go self.eventMux.Post(logs)
} }
go self.eventMux.Post(statedb.Logs())
return receipt, txGas, err return receipt, txGas, err
} }
@ -179,7 +178,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
return return
} }
receipts, err := sm.TransitionState(state, parent, block) receipts, err := sm.TransitionState(state, parent, block, false)
if err != nil { if err != nil {
return 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) 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() { if block.Time() < parent.Time() {
return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().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 ( var (
parent = sm.bc.GetBlock(block.Header().ParentHash) 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, true)
sm.TransitionState(state, parent, block)
sm.AccumulateRewards(state, block, parent) sm.AccumulateRewards(state, block, parent)
return state.Logs(), nil return state.Logs(), nil

131
core/chain_makers.go Normal file
View File

@ -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
}

View File

@ -85,12 +85,14 @@ type ChainManager struct {
lastBlockHash []byte lastBlockHash []byte
transState *state.StateDB transState *state.StateDB
txState *state.StateDB
} }
func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager { func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux} bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
bc.setLastBlock() bc.setLastBlock()
bc.transState = bc.State().Copy() bc.transState = bc.State().Copy()
bc.txState = bc.State().Copy()
return bc return bc
} }
@ -138,6 +140,19 @@ func (self *ChainManager) TransState() *state.StateDB {
return self.transState 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) { func (self *ChainManager) setTransState(statedb *state.StateDB) {
self.transState = statedb self.transState = statedb
} }
@ -268,7 +283,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
break break
} }
} }
fmt.Printf("get hash %x (%d)\n", hash, len(chain))
return return
} }
@ -363,6 +377,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
defer self.tsmu.Unlock() defer self.tsmu.Unlock()
for _, block := range chain { 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) td, err := self.processor.Process(block)
if err != nil { if err != nil {
if IsKnownBlockErr(err) { if IsKnownBlockErr(err) {
@ -377,11 +393,15 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
} }
block.Td = td block.Td = td
var chain, split bool var canonical, split bool
self.mu.Lock() 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) self.write(block)
cblock := self.currentBlock 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 td.Cmp(self.td) > 0 {
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 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) 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.setTotalDifficulty(td)
self.insert(block) self.insert(block)
chain = true canonical = true
} }
} }
self.mu.Unlock() self.mu.Unlock()
if chain { if canonical {
self.setTransState(state.New(block.Root(), self.db))
self.eventMux.Post(ChainEvent{block, td}) self.eventMux.Post(ChainEvent{block, td})
} }
if split { if split {
self.setTransState(state.New(block.Root(), self.db)) self.setTxState(state.New(block.Root(), self.db))
self.eventMux.Post(ChainSplitEvent{block}) self.eventMux.Post(ChainSplitEvent{block})
} }
} }

View File

@ -3,6 +3,7 @@ package core
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"math/big"
"os" "os"
"path" "path"
"runtime" "runtime"
@ -13,7 +14,9 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/state"
) )
func init() { func init() {
@ -21,6 +24,61 @@ func init() {
ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH") 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) { 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) 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 { if err != nil {
@ -45,6 +103,128 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *
done <- true 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) { func TestChainInsertions(t *testing.T) {
t.Skip() // travil fails. t.Skip() // travil fails.

View File

@ -111,14 +111,14 @@ func (self *Filter) Find() state.Logs {
// current parameters // current parameters
if self.bloomFilter(block) { if self.bloomFilter(block) {
// Get the logs of the block // Get the logs of the block
logs, err := self.eth.BlockProcessor().GetLogs(block) unfiltered, err := self.eth.BlockProcessor().GetLogs(block)
if err != nil { if err != nil {
chainlogger.Warnln("err: filter get logs ", err) chainlogger.Warnln("err: filter get logs ", err)
break break
} }
logs = append(logs, self.FilterLogs(logs)...) logs = append(logs, self.FilterLogs(unfiltered)...)
} }
block = self.eth.ChainManager().GetBlock(block.ParentHash()) block = self.eth.ChainManager().GetBlock(block.ParentHash())
@ -146,7 +146,6 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
Logs: Logs:
for _, log := range logs { for _, log := range logs {
if !includes(self.address, log.Address()) { if !includes(self.address, log.Address()) {
//if !bytes.Equal(self.address, log.Address()) {
continue continue
} }

View File

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

View File

@ -117,8 +117,13 @@ func (self *TxPool) add(tx *types.Transaction) error {
} else { } else {
to = "[NEW_CONTRACT]" to = "[NEW_CONTRACT]"
} }
var from string
txplogger.Debugf("(t) %x => %s (%v) %x\n", tx.From()[:4], to, tx.Value, tx.Hash()) 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 // Notify the subscribers
go self.eventMux.Post(TxPreEvent{tx}) go self.eventMux.Post(TxPreEvent{tx})

View File

@ -30,7 +30,6 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"os/user"
"path" "path"
) )
@ -48,12 +47,6 @@ type keyStorePlain struct {
keysDirPath string 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 { func NewKeyStorePlain(path string) KeyStore2 {
return &keyStorePlain{path} return &keyStorePlain{path}
} }
@ -126,8 +119,11 @@ func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
} }
addresses = make([][]byte, len(fileInfos)) addresses = make([][]byte, len(fileInfos))
for i, fileInfo := range fileInfos { for i, fileInfo := range fileInfos {
addresses[i] = make([]byte, 40) address, err := hex.DecodeString(fileInfo.Name())
addresses[i] = []byte(fileInfo.Name()) if err != nil {
continue
}
addresses[i] = address
} }
return addresses, err return addresses, err
} }

View File

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

View File

@ -3,6 +3,8 @@ package eth
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt" "fmt"
"io/ioutil"
"path"
"strings" "strings"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
@ -25,7 +27,10 @@ var (
jsonlogger = ethlogger.NewJsonLogger() jsonlogger = ethlogger.NewJsonLogger()
defaultBootNodes = []*discover.Node{ defaultBootNodes = []*discover.Node{
// ETH/DEV cmd/bootnode
discover.MustParseNode("enode://6cdd090303f394a1cac34ecc9f7cda18127eafa2a3a06de39f6d920b0e583e062a7362097c7c65ee490a758b442acd5c80c6fce4b148c6a391e946b45131365b@54.169.166.226:30303"), 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 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 { type Ethereum struct {
// Channel for shutting down the ethereum // Channel for shutting down the ethereum
shutdownChan chan bool shutdownChan chan bool
@ -121,7 +147,8 @@ func New(config *Config) (*Ethereum, error) {
d, _ := db.Get([]byte("ProtocolVersion")) d, _ := db.Get([]byte("ProtocolVersion"))
protov := ethutil.NewValue(d).Uint() protov := ethutil.NewValue(d).Uint()
if protov != ProtocolVersion && protov != 0 { 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 // Create new keymanager
@ -161,18 +188,16 @@ func New(config *Config) (*Ethereum, error) {
insertChain := eth.chainManager.InsertChain insertChain := eth.chainManager.InsertChain
eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify) 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) ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
protocols := []p2p.Protocol{ethProto} protocols := []p2p.Protocol{ethProto}
if config.Shh { if config.Shh {
protocols = append(protocols, eth.whisper.Protocol()) 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{ eth.net = &p2p.Server{
PrivateKey: netprv, PrivateKey: netprv,
Name: config.Name, Name: config.Name,

View File

@ -3,10 +3,51 @@ package ethutil
import ( import (
"fmt" "fmt"
"math/big" "math/big"
"os"
"os/user"
"path"
"path/filepath"
"runtime" "runtime"
"time" "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 { func IsWindows() bool {
return runtime.GOOS == "windows" return runtime.GOOS == "windows"
} }

View File

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

View File

@ -29,6 +29,3 @@ if ls $dir/*.go &> /dev/null; then
fi fi
fi fi
done done
go tool cover -func profile.cov

View File

@ -197,7 +197,7 @@ gasLimit:
} }
self.eth.TxPool().RemoveSet(remove) self.eth.TxPool().RemoveSet(remove)
self.current.coinbase.AddAmount(core.BlockReward) self.current.coinbase.AddBalance(core.BlockReward)
self.current.state.Update(ethutil.Big0) self.current.state.Update(ethutil.Big0)
self.push() self.push()
@ -225,7 +225,7 @@ func (self *worker) commitUncle(uncle *types.Header) error {
} }
uncleAccount := self.current.state.GetAccount(uncle.Coinbase) uncleAccount := self.current.state.GetAccount(uncle.Coinbase)
uncleAccount.AddAmount(uncleReward) uncleAccount.AddBalance(uncleReward)
self.current.coinbase.AddBalance(uncleReward) self.current.coinbase.AddBalance(uncleReward)

View File

@ -20,18 +20,24 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/event/filter" "github.com/ethereum/go-ethereum/event/filter"
"github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/ui"
"github.com/ethereum/go-ethereum/xeth" "github.com/ethereum/go-ethereum/xeth"
) )
const ( var (
defaultGasPrice = "10000000000000" defaultGasPrice = big.NewInt(10000000000000)
defaultGas = "10000" defaultGas = big.NewInt(10000)
filterTickerTime = 15 * time.Second
) )
type EthereumApi struct { type EthereumApi struct {
xeth *xeth.XEth eth *xeth.XEth
xethMu sync.RWMutex
mux *event.TypeMux
quit chan struct{} quit chan struct{}
filterManager *filter.FilterManager filterManager *filter.FilterManager
@ -45,17 +51,21 @@ type EthereumApi struct {
register map[string][]*NewTxArgs register map[string][]*NewTxArgs
db ethutil.Database db ethutil.Database
defaultBlockAge int64
} }
func NewEthereumApi(eth *xeth.XEth) *EthereumApi { func NewEthereumApi(eth *xeth.XEth) *EthereumApi {
db, _ := ethdb.NewLDBDatabase("dapps") db, _ := ethdb.NewLDBDatabase("dapps")
api := &EthereumApi{ api := &EthereumApi{
xeth: eth, eth: eth,
quit: make(chan struct{}), mux: eth.Backend().EventMux(),
filterManager: filter.NewFilterManager(eth.Backend().EventMux()), quit: make(chan struct{}),
logs: make(map[int]*logFilter), filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
messages: make(map[int]*whisperFilter), logs: make(map[int]*logFilter),
db: db, messages: make(map[int]*whisperFilter),
db: db,
defaultBlockAge: -1,
} }
go api.filterManager.Start() go api.filterManager.Start()
go api.start() go api.start()
@ -63,6 +73,64 @@ func NewEthereumApi(eth *xeth.XEth) *EthereumApi {
return api 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 { func (self *EthereumApi) Register(args string, reply *interface{}) error {
self.regmut.Lock() self.regmut.Lock()
defer self.regmut.Unlock() 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 { func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error {
var id int var id int
filter := core.NewFilter(self.xeth.Backend()) filter := core.NewFilter(self.xeth().Backend())
filter.SetOptions(toFilterOptions(args)) filter.SetOptions(toFilterOptions(args))
filter.LogsCallback = func(logs state.Logs) { filter.LogsCallback = func(logs state.Logs) {
self.logMut.Lock() 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 { func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error {
var id int var id int
filter := core.NewFilter(self.xeth.Backend()) filter := core.NewFilter(self.xeth().Backend())
callback := func(block *types.Block) { callback := func(block *types.Block) {
self.logMut.Lock() self.logMut.Lock()
defer self.logMut.Unlock() defer self.logMut.Unlock()
if self.logs[id] == nil {
self.logs[id] = &logFilter{timeout: time.Now()}
}
self.logs[id].add(&state.StateLog{}) self.logs[id].add(&state.StateLog{})
} }
if args == "pending" { if args == "pending" {
@ -139,6 +203,7 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error
} }
id = self.filterManager.InstallFilter(filter) id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()}
*reply = id *reply = id
return nil return nil
@ -167,42 +232,64 @@ func (self *EthereumApi) Logs(id int, reply *interface{}) error {
return nil return nil
} }
func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error {
err := args.requirements() filter := core.NewFilter(self.xeth().Backend())
if err != nil { filter.SetOptions(toFilterOptions(args))
return err
}
if args.BlockNumber > 0 { *reply = toLogs(filter.Find())
*reply = p.xeth.BlockByNumber(args.BlockNumber)
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 { } else {
*reply = p.xeth.BlockByHash(args.Hash) *reply = p.xeth().BlockByNumber(args.BlockNumber)
} }
return nil return nil
} }
func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
if len(args.Gas) == 0 { if len(args.Gas) == 0 {
args.Gas = defaultGas args.Gas = defaultGas.String()
} }
if len(args.GasPrice) == 0 { if len(args.GasPrice) == 0 {
args.GasPrice = defaultGasPrice args.GasPrice = defaultGasPrice.String()
} }
// TODO if no_private_key then // TODO if no_private_key then
if _, exists := p.register[args.From]; exists { //if _, exists := p.register[args.From]; exists {
p.register[args.From] = append(p.register[args.From], args) // p.register[args.From] = append(p.register[args.From], args)
} else { //} else {
result, _ := p.xeth.Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) /*
*reply = result 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 return nil
} }
func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error { 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 { if err != nil {
return err return err
} }
@ -216,7 +303,7 @@ func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
if err != nil { if err != nil {
return err return err
} }
result, _ := p.xeth.PushTx(args.Tx) result, _ := p.xeth().PushTx(args.Tx)
*reply = result *reply = result
return nil return nil
} }
@ -227,7 +314,7 @@ func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error {
return err return err
} }
state := p.xeth.State().SafeGet(args.Address) state := p.xeth().State().SafeGet(args.Address)
value := state.StorageString(args.Key) value := state.StorageString(args.Key)
var hx string var hx string
@ -249,42 +336,55 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) err
return err return err
} }
*reply = p.xeth.State().SafeGet(args.Address).Storage() *reply = p.xeth().State().SafeGet(args.Address).Storage()
return nil return nil
} }
func (p *EthereumApi) GetPeerCount(reply *interface{}) error { func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
*reply = p.xeth.PeerCount() *reply = p.xeth().PeerCount()
return nil return nil
} }
func (p *EthereumApi) GetIsListening(reply *interface{}) error { func (p *EthereumApi) GetIsListening(reply *interface{}) error {
*reply = p.xeth.IsListening() *reply = p.xeth().IsListening()
return nil return nil
} }
func (p *EthereumApi) GetCoinbase(reply *interface{}) error { func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
*reply = p.xeth.Coinbase() *reply = p.xeth().Coinbase()
return nil return nil
} }
func (p *EthereumApi) Accounts(reply *interface{}) error { func (p *EthereumApi) Accounts(reply *interface{}) error {
*reply = p.xeth.Accounts() *reply = p.xeth().Accounts()
return nil return nil
} }
func (p *EthereumApi) GetIsMining(reply *interface{}) error { func (p *EthereumApi) GetIsMining(reply *interface{}) error {
*reply = p.xeth.IsMining() *reply = p.xeth().IsMining()
return nil return nil
} }
func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error { 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 return nil
} }
func (p *EthereumApi) BlockNumber(reply *interface{}) error { func (p *EthereumApi) BlockNumber(reply *interface{}) error {
*reply = p.xeth.Backend().ChainManager().CurrentBlock().Number() *reply = p.xeth().Backend().ChainManager().CurrentBlock().Number()
return nil return nil
} }
@ -293,7 +393,7 @@ func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) err
if err != nil { if err != nil {
return err return err
} }
*reply = p.xeth.TxCountAt(args.Address) *reply = p.xeth().TxCountAt(args.Address)
return nil return nil
} }
@ -302,7 +402,7 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) err
if err != nil { if err != nil {
return err return err
} }
state := p.xeth.State().SafeGet(args.Address) state := p.xeth().State().SafeGet(args.Address)
*reply = toHex(state.Balance().Bytes()) *reply = toHex(state.Balance().Bytes())
return nil return nil
} }
@ -312,7 +412,7 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
if err != nil { if err != nil {
return err return err
} }
*reply = p.xeth.CodeAt(args.Address) *reply = p.xeth().CodeAt(args.Address)
return nil return nil
} }
@ -359,7 +459,7 @@ func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error {
} }
func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error { func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error {
*reply = p.xeth.Whisper().NewIdentity() *reply = p.xeth().Whisper().NewIdentity()
return nil return nil
} }
@ -368,12 +468,10 @@ func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) e
args.Fn = func(msg xeth.WhisperMessage) { args.Fn = func(msg xeth.WhisperMessage) {
p.messagesMut.Lock() p.messagesMut.Lock()
defer p.messagesMut.Unlock() 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) 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 *reply = id
return nil return nil
} }
@ -390,7 +488,7 @@ func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error {
} }
func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, 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 { if err != nil {
return err return err
} }
@ -400,17 +498,17 @@ func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{})
} }
func (p *EthereumApi) HasWhisperIdentity(args string, reply *interface{}) error { func (p *EthereumApi) HasWhisperIdentity(args string, reply *interface{}) error {
*reply = p.xeth.Whisper().HasIdentity(args) *reply = p.xeth().Whisper().HasIdentity(args)
return nil return nil
} }
func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error { func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error {
*reply = p.xeth.Whisper().Messages(id) *reply = p.xeth().Whisper().Messages(id)
return nil return nil
} }
func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { 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) rpclogger.DebugDetailf("%T %s", req.Params, req.Params)
switch req.Method { switch req.Method {
case "eth_coinbase": case "eth_coinbase":
@ -425,6 +523,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
return err return err
} }
return p.SetMining(args, reply) 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": case "eth_peerCount":
return p.GetPeerCount(reply) return p.GetPeerCount(reply)
case "eth_number": case "eth_number":
@ -509,8 +615,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
return err return err
} }
return p.Logs(args, reply) 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": case "eth_gasPrice":
*reply = defaultGasPrice *reply = toHex(defaultGasPrice.Bytes())
return nil return nil
case "eth_register": case "eth_register":
args, err := req.ToRegisterArgs() args, err := req.ToRegisterArgs()
@ -589,42 +701,34 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
} }
return p.WhisperMessages(args, reply) return p.WhisperMessages(args, reply)
default: default:
return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method)) return NewErrorWithMessage(errNotImplemented, req.Method)
} }
rpclogger.DebugDetailf("Reply: %T %s", reply, reply) rpclogger.DebugDetailf("Reply: %T %s", reply, reply)
return nil return nil
} }
var filterTickerTime = 15 * time.Second func (self *EthereumApi) xeth() *xeth.XEth {
self.xethMu.RLock()
defer self.xethMu.RUnlock()
func (self *EthereumApi) start() { return self.eth
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)
}
}
for id, filter := range self.messages { func (self *EthereumApi) useState(statedb *state.StateDB) {
if time.Since(filter.timeout) > 20*time.Second { self.xethMu.Lock()
delete(self.messages, id) defer self.xethMu.Unlock()
}
} self.eth = self.eth.UseState(statedb)
self.logMut.Unlock() }
self.messagesMut.Unlock()
case <-self.quit: func t(f ui.Frontend) {
break done // Call the password dialog
} ret, err := f.Call("PasswordDialog")
if err != nil {
fmt.Println(err)
} }
} // Get the first argument
t, _ := ret.Get(0)
func (self *EthereumApi) stop() { fmt.Println("return:", t)
close(self.quit)
} }

View File

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

View File

@ -19,14 +19,7 @@ func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) {
obj.Hash = argstr obj.Hash = argstr
return return
} }
return NewErrorResponse(ErrorDecodeArgs) return errDecodeArgs
}
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
} }
type NewTxArgs struct { type NewTxArgs struct {
@ -64,7 +57,7 @@ func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
return return
} }
return NewErrorResponse(ErrorDecodeArgs) return errDecodeArgs
} }
type PushTxArgs struct { type PushTxArgs struct {
@ -77,12 +70,12 @@ func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) {
obj.Tx = arg0 obj.Tx = arg0
return return
} }
return NewErrorResponse(ErrorDecodeArgs) return errDecodeArgs
} }
func (a *PushTxArgs) requirementsPushTx() error { func (a *PushTxArgs) requirementsPushTx() error {
if a.Tx == "" { if a.Tx == "" {
return NewErrorResponse("PushTx requires a 'tx' as argument") return NewErrorWithMessage(errArguments, "PushTx requires a 'tx' as argument")
} }
return nil return nil
} }
@ -93,14 +86,14 @@ type GetStorageArgs struct {
func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
if err = json.Unmarshal(b, &obj.Address); err != nil { if err = json.Unmarshal(b, &obj.Address); err != nil {
return NewErrorResponse(ErrorDecodeArgs) return errDecodeArgs
} }
return return
} }
func (a *GetStorageArgs) requirements() error { func (a *GetStorageArgs) requirements() error {
if len(a.Address) == 0 { 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 return nil
} }
@ -116,64 +109,39 @@ func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) {
obj.Address = arg0 obj.Address = arg0
return return
} }
return NewErrorResponse(ErrorDecodeArgs) return errDecodeArgs
} }
func (a *GetStateArgs) requirements() error { func (a *GetStateArgs) requirements() error {
if a.Address == "" { 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 == "" { if a.Key == "" {
return NewErrorResponse("GetStorageAt requires an 'key' value as argument") return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'key' value as argument")
} }
return nil return nil
} }
type GetStorageAtRes struct {
Key string `json:"key"`
Value string `json:"value"`
}
type GetTxCountArgs struct { type GetTxCountArgs struct {
Address string `json:"address"` Address string `json:"address"`
} }
// type GetTxCountRes struct {
// Nonce int `json:"nonce"`
// }
func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := "" arg0 := ""
if err = json.Unmarshal(b, &arg0); err == nil { if err = json.Unmarshal(b, &arg0); err == nil {
obj.Address = arg0 obj.Address = arg0
return return
} }
return NewErrorResponse("Could not determine JSON parameters") return errDecodeArgs
} }
func (a *GetTxCountArgs) requirements() error { func (a *GetTxCountArgs) requirements() error {
if a.Address == "" { if a.Address == "" {
return NewErrorResponse("GetTxCountAt requires an 'address' value as argument") return NewErrorWithMessage(errArguments, "GetTxCountAt requires an 'address' value as argument")
} }
return nil 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 { type GetBalanceArgs struct {
Address string Address string
} }
@ -184,21 +152,16 @@ func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
obj.Address = arg0 obj.Address = arg0
return return
} }
return NewErrorResponse("Could not determine JSON parameters") return errDecodeArgs
} }
func (a *GetBalanceArgs) requirements() error { func (a *GetBalanceArgs) requirements() error {
if a.Address == "" { if a.Address == "" {
return NewErrorResponse("GetBalanceAt requires an 'address' value as argument") return NewErrorWithMessage(errArguments, "GetBalanceAt requires an 'address' value as argument")
} }
return nil return nil
} }
type BalanceRes struct {
Balance string `json:"balance"`
Address string `json:"address"`
}
type GetCodeAtArgs struct { type GetCodeAtArgs struct {
Address string Address string
} }
@ -209,12 +172,12 @@ func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) {
obj.Address = arg0 obj.Address = arg0
return return
} }
return NewErrorResponse(ErrorDecodeArgs) return errDecodeArgs
} }
func (a *GetCodeAtArgs) requirements() error { func (a *GetCodeAtArgs) requirements() error {
if a.Address == "" { if a.Address == "" {
return NewErrorResponse("GetCodeAt requires an 'address' value as argument") return NewErrorWithMessage(errArguments, "GetCodeAt requires an 'address' value as argument")
} }
return nil return nil
} }
@ -225,7 +188,7 @@ type Sha3Args struct {
func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) { func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) {
if err = json.Unmarshal(b, &obj.Data); err != nil { if err = json.Unmarshal(b, &obj.Data); err != nil {
return NewErrorResponse(ErrorDecodeArgs) return errDecodeArgs
} }
return return
} }
@ -277,10 +240,10 @@ type DbArgs struct {
func (a *DbArgs) requirements() error { func (a *DbArgs) requirements() error {
if len(a.Database) == 0 { 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 { 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 return nil
} }

View File

@ -92,7 +92,7 @@ func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler {
reqParsed, reqerr := JSON.ParseRequestBody(req) reqParsed, reqerr := JSON.ParseRequestBody(req)
if reqerr != nil { 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}) JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
return return
} }

View File

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

View File

@ -82,8 +82,9 @@ type RpcServer interface {
type Log struct { type Log struct {
Address string `json:"address"` Address string `json:"address"`
Topic []string `json:"topics"` Topic []string `json:"topic"`
Data string `json:"data"` Data string `json:"data"`
Number uint64 `json:"number"`
} }
func toLogs(logs state.Logs) (ls []Log) { 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.Topic = make([]string, len(log.Topics()))
l.Address = toHex(log.Address()) l.Address = toHex(log.Address())
l.Data = toHex(log.Data()) l.Data = toHex(log.Data())
l.Number = log.Number()
for j, topic := range log.Topics() { for j, topic := range log.Topics() {
l.Topic[j] = toHex(topic) l.Topic[j] = toHex(topic)
} }
@ -106,6 +108,7 @@ func toLogs(logs state.Logs) (ls []Log) {
type whisperFilter struct { type whisperFilter struct {
messages []xeth.WhisperMessage messages []xeth.WhisperMessage
timeout time.Time timeout time.Time
id int
} }
func (w *whisperFilter) add(msgs ...xeth.WhisperMessage) { func (w *whisperFilter) add(msgs ...xeth.WhisperMessage) {
@ -121,6 +124,7 @@ func (w *whisperFilter) get() []xeth.WhisperMessage {
type logFilter struct { type logFilter struct {
logs state.Logs logs state.Logs
timeout time.Time timeout time.Time
id int
} }
func (l *logFilter) add(logs ...state.Log) { func (l *logFilter) add(logs ...state.Log) {

View File

@ -99,7 +99,7 @@ func sockHandler(api *rpc.EthereumApi) websocket.Handler {
// reqParsed, reqerr := JSON.ParseRequestBody(conn.Request()) // reqParsed, reqerr := JSON.ParseRequestBody(conn.Request())
if err := websocket.JSON.Receive(conn, &reqParsed); err != nil { 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}) JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
continue continue
} }

View File

@ -35,7 +35,7 @@ func (self *StateDB) Dump() []byte {
storageIt := stateObject.State.trie.Iterator() storageIt := stateObject.State.trie.Iterator()
for storageIt.Next() { 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 world.Accounts[ethutil.Bytes2Hex(it.Key)] = account
} }

View File

@ -12,16 +12,19 @@ type Log interface {
Address() []byte Address() []byte
Topics() [][]byte Topics() [][]byte
Data() []byte Data() []byte
Number() uint64
} }
type StateLog struct { type StateLog struct {
address []byte address []byte
topics [][]byte topics [][]byte
data []byte data []byte
number uint64
} }
func NewLog(address []byte, topics [][]byte, data []byte) *StateLog { func NewLog(address []byte, topics [][]byte, data []byte, number uint64) *StateLog {
return &StateLog{address, topics, data} return &StateLog{address, topics, data, number}
} }
func (self *StateLog) Address() []byte { func (self *StateLog) Address() []byte {
@ -36,6 +39,10 @@ func (self *StateLog) Data() []byte {
return self.data return self.data
} }
func (self *StateLog) Number() uint64 {
return self.number
}
func NewLogFromValue(decoder *ethutil.Value) *StateLog { func NewLogFromValue(decoder *ethutil.Value) *StateLog {
log := &StateLog{ log := &StateLog{
address: decoder.Get(0).Bytes(), address: decoder.Get(0).Bytes(),

View File

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

18
ui/frontend.go Normal file
View File

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

View File

@ -54,6 +54,7 @@ type Log struct {
address []byte address []byte
topics [][]byte topics [][]byte
data []byte data []byte
log uint64
} }
func (self *Log) Address() []byte { func (self *Log) Address() []byte {
@ -68,6 +69,10 @@ func (self *Log) Data() []byte {
return self.data return self.data
} }
func (self *Log) Number() uint64 {
return self.log
}
func (self *Log) RlpData() interface{} { func (self *Log) RlpData() interface{} {
return []interface{}{self.address, ethutil.ByteSliceToInterface(self.topics), self.data} return []interface{}{self.address, ethutil.ByteSliceToInterface(self.topics), self.data}
} }

View File

@ -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()) 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.env.AddLog(log)
self.Printf(" => %v", 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() addr = ref.Address()
fmt.Printf("CREATE %X\n", addr)
stack.Push(ethutil.BigD(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) self.Printf(" => (%x) %v", receiver.Address()[:4], balance)
receiver.AddAmount(balance) receiver.AddBalance(balance)
statedb.Delete(context.Address()) statedb.Delete(context.Address())
fallthrough fallthrough
@ -779,9 +780,9 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
// Stack Check, memory resize & gas phase // Stack Check, memory resize & gas phase
switch op { switch op {
// Stack checks only // Stack checks only
case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1 case ISZERO, CALLDATALOAD, POP, JUMP, NOT, EXTCODESIZE, BLOCKHASH: // 1
stack.require(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) stack.require(2)
case ADDMOD, MULMOD: // 3 case ADDMOD, MULMOD: // 3
stack.require(3) stack.require(3)
@ -828,7 +829,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
// 0 => non 0 // 0 => non 0
mult = ethutil.Big3 mult = ethutil.Big3
} else if len(val) > 0 && len(y.Bytes()) == 0 { } else if len(val) > 0 && len(y.Bytes()) == 0 {
statedb.Refund(caller.Address(), GasSStoreRefund) statedb.Refund(self.env.Origin(), GasSStoreRefund)
mult = ethutil.Big0 mult = ethutil.Big0
} else { } else {
@ -859,7 +860,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
additionalGas.Set(stack.data[stack.Len()-2]) additionalGas.Set(stack.data[stack.Len()-2])
case CALLDATACOPY: case CALLDATACOPY:
stack.require(2) stack.require(3)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
additionalGas.Set(stack.data[stack.Len()-3]) additionalGas.Set(stack.data[stack.Len()-3])

View File

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

View File

@ -3,19 +3,20 @@ package xeth
import "github.com/ethereum/go-ethereum/state" import "github.com/ethereum/go-ethereum/state"
type State struct { type State struct {
xeth *XEth xeth *XEth
state *state.StateDB
} }
func NewState(xeth *XEth) *State { func NewState(xeth *XEth, statedb *state.StateDB) *State {
return &State{xeth} return &State{xeth, statedb}
} }
func (self *State) State() *state.StateDB { func (self *State) State() *state.StateDB {
return self.xeth.chainManager.TransState() return self.state
} }
func (self *State) Get(addr string) *Object { 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 { 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 { func (self *State) safeGet(addr string) *state.StateObject {
object := self.State().GetStateObject(fromHex(addr)) object := self.state.GetStateObject(fromHex(addr))
if object == nil { if object == nil {
object = state.NewStateObject(fromHex(addr), self.xeth.eth.Db()) object = state.NewStateObject(fromHex(addr), self.xeth.eth.Db())
} }

View File

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