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
go:
- 1.4.1
- 1.4.2
before_install:
- sudo add-apt-repository ppa:beineri/opt-qt54 -y
- sudo add-apt-repository ppa:beineri/opt-qt541 -y
- sudo apt-get update -qq
- sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine
install:
# - go get code.google.com/p/go.tools/cmd/goimports
# - go get github.com/golang/lint/golint
# - go get golang.org/x/tools/cmd/vet
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
- go get github.com/mattn/goveralls
before_script:
# - gofmt -l -w .
# - goimports -l -w .
# - golint .
# - go vet ./...
# - go test -race ./...
script:

11
Godeps/Godeps.json generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -964,7 +964,7 @@ ApplicationWindow {
anchors.top: parent.top
anchors.topMargin: 30
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"
"log"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
"bitbucket.org/kardianos/osext"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/vm"
@ -68,38 +66,7 @@ var (
// flags specific to gui client
var AssetPath string
//TODO: If we re-use the one defined in cmd.go the binary osx image crashes. If somebody finds out why we can dry this up.
func defaultAssetPath() string {
var assetPath string
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/mist"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
return assetPath
}
func defaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereum")
}
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini")
func Init() {
// TODO: move common flag processing to cmd/utils
@ -121,12 +88,12 @@ func Init() {
flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)")
flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use")
flag.StringVar(&Datadir, "datadir", ethutil.DefaultDataDir(), "specifies the datadir to use")
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory")
flag.StringVar(&AssetPath, "asset_path", ethutil.DefaultAssetPath(), "absolute path to GUI assets directory")
// Network stuff
var (

View File

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

View File

@ -25,12 +25,8 @@ import (
"fmt"
"os"
"os/signal"
"path"
"path/filepath"
"regexp"
"runtime"
"bitbucket.org/kardianos/osext"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
@ -132,31 +128,6 @@ func StartEthereum(ethereum *eth.Ethereum) {
})
}
func DefaultAssetPath() string {
var assetPath string
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/mist"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
return assetPath
}
func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
var err error
@ -272,7 +243,7 @@ func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
parent := ethereum.ChainManager().GetBlock(block.ParentHash())
statedb := state.New(parent.Root(), ethereum.Db())
_, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block)
_, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block, true)
if err != nil {
return err
}

View File

@ -50,7 +50,6 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
sm := &BlockProcessor{
db: db,
mem: make(map[string]*big.Int),
//Pow: &ethash.Ethash{},
Pow: ezp.New(),
bc: chainManager,
eventMux: eventMux,
@ -60,12 +59,12 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
return sm
}
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) {
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
coinbase.SetGasPool(CalcGasLimit(parent, block))
coinbase.SetGasPool(block.Header().GasLimit)
// Process the transactions on to parent state
receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
if err != nil {
return nil, err
}
@ -100,10 +99,10 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
// Notify all subscribers
if !transientProcess {
go self.eventMux.Post(TxPostEvent{tx})
logs := statedb.Logs()
go self.eventMux.Post(logs)
}
go self.eventMux.Post(statedb.Logs())
return receipt, txGas, err
}
@ -179,7 +178,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
return
}
receipts, err := sm.TransitionState(state, parent, block)
receipts, err := sm.TransitionState(state, parent, block, false)
if err != nil {
return
}
@ -248,6 +247,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
}
expl := CalcGasLimit(parent, block)
if expl.Cmp(block.Header().GasLimit) != 0 {
return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl)
}
if block.Time() < parent.Time() {
return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time)
}
@ -316,13 +320,10 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
var (
parent = sm.bc.GetBlock(block.Header().ParentHash)
//state = state.New(parent.Trie().Copy())
state = state.New(parent.Root(), sm.db)
)
defer state.Reset()
sm.TransitionState(state, parent, block)
sm.TransitionState(state, parent, block, true)
sm.AccumulateRewards(state, block, parent)
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
transState *state.StateDB
txState *state.StateDB
}
func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
bc.setLastBlock()
bc.transState = bc.State().Copy()
bc.txState = bc.State().Copy()
return bc
}
@ -138,6 +140,19 @@ func (self *ChainManager) TransState() *state.StateDB {
return self.transState
}
func (self *ChainManager) TxState() *state.StateDB {
self.tsmu.RLock()
defer self.tsmu.RUnlock()
return self.txState
}
func (self *ChainManager) setTxState(state *state.StateDB) {
self.tsmu.Lock()
defer self.tsmu.Unlock()
self.txState = state
}
func (self *ChainManager) setTransState(statedb *state.StateDB) {
self.transState = statedb
}
@ -268,7 +283,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
break
}
}
fmt.Printf("get hash %x (%d)\n", hash, len(chain))
return
}
@ -363,6 +377,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
defer self.tsmu.Unlock()
for _, block := range chain {
// Call in to the block processor and check for errors. It's likely that if one block fails
// all others will fail too (unless a known block is returned).
td, err := self.processor.Process(block)
if err != nil {
if IsKnownBlockErr(err) {
@ -377,11 +393,15 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
}
block.Td = td
var chain, split bool
var canonical, split bool
self.mu.Lock()
{
// Write block to database. Eventually we'll have to improve on this and throw away blocks that are
// not in the canonical chain.
self.write(block)
cblock := self.currentBlock
// Compare the TD of the last known block in the canonical chain to make sure it's greater.
// At this point it's possible that a different chain (fork) becomes the new canonical chain.
if td.Cmp(self.td) > 0 {
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
@ -391,17 +411,18 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
self.setTotalDifficulty(td)
self.insert(block)
chain = true
canonical = true
}
}
self.mu.Unlock()
if chain {
if canonical {
self.setTransState(state.New(block.Root(), self.db))
self.eventMux.Post(ChainEvent{block, td})
}
if split {
self.setTransState(state.New(block.Root(), self.db))
self.setTxState(state.New(block.Root(), self.db))
self.eventMux.Post(ChainSplitEvent{block})
}
}

View File

@ -3,6 +3,7 @@ package core
import (
"bytes"
"fmt"
"math/big"
"os"
"path"
"runtime"
@ -13,7 +14,9 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/state"
)
func init() {
@ -21,6 +24,61 @@ func init() {
ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
}
// Test fork of length N starting from block i
func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) {
fmt.Println("Testing Fork!")
var b *types.Block = nil
if i > 0 {
b = bman.bc.GetBlockByNumber(uint64(i))
}
_ = b
// switch databases to process the new chain
db, err := ethdb.NewMemDatabase()
if err != nil {
t.Fatal("Failed to create db:", err)
}
// copy old chain up to i into new db with deterministic canonical
bman2, err := newCanonical(i, db)
if err != nil {
t.Fatal("could not make new canonical in testFork", err)
}
bman2.bc.SetProcessor(bman2)
parent := bman2.bc.CurrentBlock()
chainB := makeChain(bman2, parent, N, db)
bman2.bc.InsertChain(chainB)
tdpre := bman.bc.Td()
td, err := testChain(chainB, bman)
if err != nil {
t.Fatal("expected chainB not to give errors:", err)
}
// Compare difficulties
f(tdpre, td)
}
func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
td := new(big.Int)
for _, block := range chainB {
td2, err := bman.bc.processor.Process(block)
if err != nil {
if IsKnownBlockErr(err) {
continue
}
return nil, err
}
block.Td = td2
td = td2
bman.bc.mu.Lock()
{
bman.bc.write(block)
}
bman.bc.mu.Unlock()
}
return td, nil
}
func loadChain(fn string, t *testing.T) (types.Blocks, error) {
fh, err := os.OpenFile(path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm)
if err != nil {
@ -45,6 +103,128 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *
done <- true
}
func TestExtendCanonical(t *testing.T) {
db, err := ethdb.NewMemDatabase()
if err != nil {
t.Fatal("Failed to create db:", err)
}
// make first chain starting from genesis
bman, err := newCanonical(5, db)
if err != nil {
t.Fatal("Could not make new canonical chain:", err)
}
f := func(td1, td2 *big.Int) {
if td2.Cmp(td1) <= 0 {
t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
}
}
// Start fork from current height (5)
testFork(t, bman, 5, 1, f)
testFork(t, bman, 5, 2, f)
testFork(t, bman, 5, 5, f)
testFork(t, bman, 5, 10, f)
}
func TestShorterFork(t *testing.T) {
db, err := ethdb.NewMemDatabase()
if err != nil {
t.Fatal("Failed to create db:", err)
}
// make first chain starting from genesis
bman, err := newCanonical(10, db)
if err != nil {
t.Fatal("Could not make new canonical chain:", err)
}
f := func(td1, td2 *big.Int) {
if td2.Cmp(td1) >= 0 {
t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1)
}
}
// Sum of numbers must be less than 10
// for this to be a shorter fork
testFork(t, bman, 0, 3, f)
testFork(t, bman, 0, 7, f)
testFork(t, bman, 1, 1, f)
testFork(t, bman, 1, 7, f)
testFork(t, bman, 5, 3, f)
testFork(t, bman, 5, 4, f)
}
func TestLongerFork(t *testing.T) {
db, err := ethdb.NewMemDatabase()
if err != nil {
t.Fatal("Failed to create db:", err)
}
// make first chain starting from genesis
bman, err := newCanonical(10, db)
if err != nil {
t.Fatal("Could not make new canonical chain:", err)
}
f := func(td1, td2 *big.Int) {
if td2.Cmp(td1) <= 0 {
t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
}
}
// Sum of numbers must be greater than 10
// for this to be a longer fork
testFork(t, bman, 0, 11, f)
testFork(t, bman, 0, 15, f)
testFork(t, bman, 1, 10, f)
testFork(t, bman, 1, 12, f)
testFork(t, bman, 5, 6, f)
testFork(t, bman, 5, 8, f)
}
func TestEqualFork(t *testing.T) {
db, err := ethdb.NewMemDatabase()
if err != nil {
t.Fatal("Failed to create db:", err)
}
bman, err := newCanonical(10, db)
if err != nil {
t.Fatal("Could not make new canonical chain:", err)
}
f := func(td1, td2 *big.Int) {
if td2.Cmp(td1) != 0 {
t.Error("expected chainB to have equal difficulty. Got", td2, "expected ", td1)
}
}
// Sum of numbers must be equal to 10
// for this to be an equal fork
testFork(t, bman, 1, 9, f)
testFork(t, bman, 2, 8, f)
testFork(t, bman, 5, 5, f)
testFork(t, bman, 6, 4, f)
testFork(t, bman, 9, 1, f)
}
func TestBrokenChain(t *testing.T) {
db, err := ethdb.NewMemDatabase()
if err != nil {
t.Fatal("Failed to create db:", err)
}
bman, err := newCanonical(10, db)
if err != nil {
t.Fatal("Could not make new canonical chain:", err)
}
db2, err := ethdb.NewMemDatabase()
if err != nil {
t.Fatal("Failed to create db:", err)
}
bman2, err := newCanonical(10, db2)
if err != nil {
t.Fatal("Could not make new canonical chain:", err)
}
bman2.bc.SetProcessor(bman2)
parent := bman2.bc.CurrentBlock()
chainB := makeChain(bman2, parent, 5, db2)
chainB = chainB[1:]
_, err = testChain(chainB, bman)
if err == nil {
t.Error("expected broken chain to return error")
}
}
func TestChainInsertions(t *testing.T) {
t.Skip() // travil fails.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,8 @@ package eth
import (
"crypto/ecdsa"
"fmt"
"io/ioutil"
"path"
"strings"
"github.com/ethereum/go-ethereum/core"
@ -25,7 +27,10 @@ var (
jsonlogger = ethlogger.NewJsonLogger()
defaultBootNodes = []*discover.Node{
// ETH/DEV cmd/bootnode
discover.MustParseNode("enode://6cdd090303f394a1cac34ecc9f7cda18127eafa2a3a06de39f6d920b0e583e062a7362097c7c65ee490a758b442acd5c80c6fce4b148c6a391e946b45131365b@54.169.166.226:30303"),
// ETH/DEV cpp-ethereum (poc-8.ethdev.com)
discover.MustParseNode("enode://4a44599974518ea5b0f14c31c4463692ac0329cb84851f3435e6d1b18ee4eae4aa495f846a0fa1219bd58035671881d44423876e57db2abd57254d0197da0ebe@5.1.83.226:30303"),
}
)
@ -77,6 +82,27 @@ func (cfg *Config) parseBootNodes() []*discover.Node {
return ns
}
func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
// use explicit key from command line args if set
if cfg.NodeKey != nil {
return cfg.NodeKey, nil
}
// use persistent key if present
keyfile := path.Join(cfg.DataDir, "nodekey")
key, err := crypto.LoadECDSA(keyfile)
if err == nil {
return key, nil
}
// no persistent key, generate and store a new one
if key, err = crypto.GenerateKey(); err != nil {
return nil, fmt.Errorf("could not generate server key: %v", err)
}
if err := ioutil.WriteFile(keyfile, crypto.FromECDSA(key), 0600); err != nil {
logger.Errorln("could not persist nodekey: ", err)
}
return key, nil
}
type Ethereum struct {
// Channel for shutting down the ethereum
shutdownChan chan bool
@ -121,7 +147,8 @@ func New(config *Config) (*Ethereum, error) {
d, _ := db.Get([]byte("ProtocolVersion"))
protov := ethutil.NewValue(d).Uint()
if protov != ProtocolVersion && protov != 0 {
return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, ethutil.Config.ExecPath+"/database")
path := path.Join(config.DataDir, "database")
return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, path)
}
// Create new keymanager
@ -161,18 +188,16 @@ func New(config *Config) (*Ethereum, error) {
insertChain := eth.chainManager.InsertChain
eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify)
netprv, err := config.nodeKey()
if err != nil {
return nil, err
}
ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
protocols := []p2p.Protocol{ethProto}
if config.Shh {
protocols = append(protocols, eth.whisper.Protocol())
}
netprv := config.NodeKey
if netprv == nil {
if netprv, err = crypto.GenerateKey(); err != nil {
return nil, fmt.Errorf("could not generate server key: %v", err)
}
}
eth.net = &p2p.Server{
PrivateKey: netprv,
Name: config.Name,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -92,7 +92,7 @@ func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler {
reqParsed, reqerr := JSON.ParseRequestBody(req)
if reqerr != nil {
jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest}
jsonerr := &rpc.RpcErrorObject{-32700, "Error: Could not parse request"}
JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
return
}

View File

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

View File

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

View File

@ -99,7 +99,7 @@ func sockHandler(api *rpc.EthereumApi) websocket.Handler {
// reqParsed, reqerr := JSON.ParseRequestBody(conn.Request())
if err := websocket.JSON.Receive(conn, &reqParsed); err != nil {
jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest}
jsonerr := &rpc.RpcErrorObject{-32700, "Error: Could not parse request"}
JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
continue
}

View File

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

View File

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

View File

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

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
topics [][]byte
data []byte
log uint64
}
func (self *Log) Address() []byte {
@ -68,6 +69,10 @@ func (self *Log) Data() []byte {
return self.data
}
func (self *Log) Number() uint64 {
return self.log
}
func (self *Log) RlpData() interface{} {
return []interface{}{self.address, ethutil.ByteSliceToInterface(self.topics), self.data}
}

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())
log := &Log{context.Address(), topics, data}
log := &Log{context.Address(), topics, data, self.env.BlockNumber().Uint64()}
self.env.AddLog(log)
self.Printf(" => %v", log)
@ -664,6 +664,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
}
addr = ref.Address()
fmt.Printf("CREATE %X\n", addr)
stack.Push(ethutil.BigD(addr))
}
@ -727,7 +728,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
self.Printf(" => (%x) %v", receiver.Address()[:4], balance)
receiver.AddAmount(balance)
receiver.AddBalance(balance)
statedb.Delete(context.Address())
fallthrough
@ -779,9 +780,9 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
// Stack Check, memory resize & gas phase
switch op {
// Stack checks only
case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1
case ISZERO, CALLDATALOAD, POP, JUMP, NOT, EXTCODESIZE, BLOCKHASH: // 1
stack.require(1)
case JUMPI, ADD, SUB, DIV, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
case JUMPI, ADD, SUB, DIV, MUL, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
stack.require(2)
case ADDMOD, MULMOD: // 3
stack.require(3)
@ -828,7 +829,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
// 0 => non 0
mult = ethutil.Big3
} else if len(val) > 0 && len(y.Bytes()) == 0 {
statedb.Refund(caller.Address(), GasSStoreRefund)
statedb.Refund(self.env.Origin(), GasSStoreRefund)
mult = ethutil.Big0
} else {
@ -859,7 +860,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
additionalGas.Set(stack.data[stack.Len()-2])
case CALLDATACOPY:
stack.require(2)
stack.require(3)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
additionalGas.Set(stack.data[stack.Len()-3])

View File

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

View File

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

View File

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