From 0e2f6691bfbbcc666c409be6b8657bd6ca475ddd Mon Sep 17 00:00:00 2001 From: Alexandre Van de Sande Date: Tue, 17 Feb 2015 17:37:26 +0100 Subject: [PATCH 01/78] Cut, Copy, Undo and Redo working in webview --- cmd/mist/assets/ext/mist.js | 9 +++++++-- cmd/mist/assets/qml/views/browser.qml | 10 ++++++---- cmd/mist/assets/qml/views/catalog.qml | 19 +++++++------------ 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/cmd/mist/assets/ext/mist.js b/cmd/mist/assets/ext/mist.js index 8734f8dc76..8589c8fc5e 100644 --- a/cmd/mist/assets/ext/mist.js +++ b/cmd/mist/assets/ext/mist.js @@ -27,9 +27,14 @@ document.onkeydown = function(evt) { } else if (evt.ctrlKey && evt.keyCode == 88) { window.document.execCommand("cut"); console.log("Ctrl-X"); - } if (evt.ctrlKey && evt.keyCode == 86) { + } else if (evt.ctrlKey && evt.keyCode == 86) { + window.document.execCommand("paste"); console.log("Ctrl-V"); - } if (evt.ctrlKey && evt.keyCode == 90) { + } else if (evt.ctrlKey && evt.keyCode == 90) { + window.document.execCommand("undo"); + console.log("Ctrl-Z"); + } else if (evt.ctrlKey && evt.shiftKey && evt.keyCode == 90) { + window.document.execCommand("redo"); console.log("Ctrl-Z"); } }; \ No newline at end of file diff --git a/cmd/mist/assets/qml/views/browser.qml b/cmd/mist/assets/qml/views/browser.qml index 54f5d755e4..edecc86963 100644 --- a/cmd/mist/assets/qml/views/browser.qml +++ b/cmd/mist/assets/qml/views/browser.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 1.0; import QtQuick.Controls.Styles 1.0 import QtQuick.Layouts 1.0; import QtWebEngine 1.0 -//import QtWebEngine.experimental 1.0 +import QtWebEngine.experimental 1.0 import QtQuick.Window 2.0; Rectangle { @@ -340,7 +340,7 @@ Rectangle { WebEngineView { objectName: "webView" id: webview - //experimental.settings.javascriptCanAccessClipboard: true + experimental.settings.javascriptCanAccessClipboard: true //experimental.settings.localContentCanAccessRemoteUrls: true anchors { left: parent.left @@ -399,7 +399,8 @@ Rectangle { onLoadingChanged: { if (loadRequest.status == WebEngineView.LoadSucceededStatus) { - webview.runJavaScript("document.title", function(pageTitle) { + + webview.runJavaScript("document.title", function(pageTitle) { menuItem.title = pageTitle; }); @@ -441,7 +442,8 @@ Rectangle { webview.runJavaScript(eth.readFile("bignumber.min.js")); webview.runJavaScript(eth.readFile("ethereum.js/dist/ethereum.js")); - + webview.runJavaScript(eth.readFile("mist.js")); + var cleanTitle = webview.url.toString() var matches = cleanTitle.match(/^[a-z]*\:\/\/([^\/?#]+)(?:[\/?#]|$)/i); var domain = matches && matches[1]; diff --git a/cmd/mist/assets/qml/views/catalog.qml b/cmd/mist/assets/qml/views/catalog.qml index 497d69ed11..29e1330742 100644 --- a/cmd/mist/assets/qml/views/catalog.qml +++ b/cmd/mist/assets/qml/views/catalog.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 1.0; import QtQuick.Controls.Styles 1.0 import QtQuick.Layouts 1.0; import QtWebEngine 1.0 -//import QtWebEngine.experimental 1.0 +import QtWebEngine.experimental 1.0 import QtQuick.Window 2.0; @@ -21,8 +21,6 @@ Rectangle { property alias windowTitle: webview.title property alias webView: webview - - property var cleanPath: false property var open: function(url) { if(!window.cleanPath) { @@ -66,9 +64,6 @@ Rectangle { } } - Component.onCompleted: { - } - Item { objectName: "root" id: root @@ -85,7 +80,7 @@ Rectangle { property var domain: "ethereum-dapp-catalog.meteor.com" url: protocol + domain - //experimental.settings.javascriptCanAccessClipboard: true + experimental.settings.javascriptCanAccessClipboard: true onJavaScriptConsoleMessage: { @@ -112,11 +107,11 @@ Rectangle { } } - // onLoadingChanged: { - // if (loadRequest.status == WebEngineView.LoadSucceededStatus) { - // webview.runJavaScript(eth.readFile("mist.js")); - // } - // } + onLoadingChanged: { + if (loadRequest.status == WebEngineView.LoadSucceededStatus) { + webview.runJavaScript(eth.readFile("mist.js")); + } + } } From acd93c29711f18787ec3392751f57ffe08b5df28 Mon Sep 17 00:00:00 2001 From: Alexandre Van de Sande Date: Wed, 18 Feb 2015 10:25:40 +0100 Subject: [PATCH 02/78] Removed console logs from mist.js also fixed an issue where it would force reloads unnecessarily --- cmd/mist/assets/ext/mist.js | 7 ++----- cmd/mist/assets/qml/main.qml | 8 ++++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cmd/mist/assets/ext/mist.js b/cmd/mist/assets/ext/mist.js index 8589c8fc5e..2fc38cdfaf 100644 --- a/cmd/mist/assets/ext/mist.js +++ b/cmd/mist/assets/ext/mist.js @@ -20,21 +20,18 @@ console.log("loaded?"); document.onkeydown = function(evt) { + // This functions keeps track of keyboard inputs in order to allow copy, paste and other features + evt = evt || window.event; if (evt.ctrlKey && evt.keyCode == 67) { window.document.execCommand("copy"); - console.log("Ctrl-C"); } else if (evt.ctrlKey && evt.keyCode == 88) { window.document.execCommand("cut"); - console.log("Ctrl-X"); } else if (evt.ctrlKey && evt.keyCode == 86) { window.document.execCommand("paste"); - console.log("Ctrl-V"); } else if (evt.ctrlKey && evt.keyCode == 90) { window.document.execCommand("undo"); - console.log("Ctrl-Z"); } else if (evt.ctrlKey && evt.shiftKey && evt.keyCode == 90) { window.document.execCommand("redo"); - console.log("Ctrl-Z"); } }; \ No newline at end of file diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index 9a6bf52738..78a6dd8469 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -132,7 +132,11 @@ ApplicationWindow { var existingDomain = matches && matches[1]; if (requestedDomain == existingDomain) { domainAlreadyOpen = true; - mainSplit.views[i].view.url = url; + + if (mainSplit.views[i].view.url != url){ + mainSplit.views[i].view.url = url; + } + activeView(mainSplit.views[i].view, mainSplit.views[i].menuItem); } } @@ -888,7 +892,7 @@ ApplicationWindow { function addPeer(peer) { peerModel.append(peer) } function setPeerCounters(text) { - peerCounterLabel.text = text + //peerCounterLabel.text = text } function timeAgo(unixTs){ From f499f343baefece18764135eb99af0c7e038ff5e Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Wed, 18 Feb 2015 10:52:23 +0100 Subject: [PATCH 03/78] Update JSON Log types --- eth/backend.go | 2 - logger/types.go | 593 ++++++++++++++++++++++++------------------------ 2 files changed, 295 insertions(+), 300 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 690c7136d2..06c64e811f 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -205,9 +205,7 @@ func (s *Ethereum) Coinbase() []byte { return nil } // TODO func (s *Ethereum) Start() error { jsonlogger.LogJson(ðlogger.LogStarting{ ClientString: s.net.Name, - Coinbase: ethutil.Bytes2Hex(s.KeyManager().Address()), ProtocolVersion: ProtocolVersion, - LogEvent: ethlogger.LogEvent{Guid: ethutil.Bytes2Hex(crypto.FromECDSAPub(&s.net.PrivateKey.PublicKey))}, }) err := s.net.Start() diff --git a/logger/types.go b/logger/types.go index 4193822312..d14a266433 100644 --- a/logger/types.go +++ b/logger/types.go @@ -7,7 +7,6 @@ import ( type utctime8601 struct{} func (utctime8601) MarshalJSON() ([]byte, error) { - // FIX This should be re-formated for proper ISO 8601 return []byte(`"` + time.Now().UTC().Format(time.RFC3339Nano)[:26] + `Z"`), nil } @@ -16,14 +15,13 @@ type JsonLog interface { } type LogEvent struct { - Guid string `json:"guid"` - Ts utctime8601 `json:"ts"` + // Guid string `json:"guid"` + Ts utctime8601 `json:"ts"` // Level string `json:"level"` } type LogStarting struct { - ClientString string `json:"version_string"` - Coinbase string `json:"coinbase"` + ClientString string `json:"client_impl"` ProtocolVersion int `json:"eth_version"` LogEvent } @@ -32,17 +30,6 @@ func (l *LogStarting) EventName() string { return "starting" } -type P2PConnecting struct { - RemoteId string `json:"remote_id"` - RemoteEndpoint string `json:"remote_endpoint"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PConnecting) EventName() string { - return "p2p.connecting" -} - type P2PConnected struct { RemoteId string `json:"remote_id"` RemoteAddress string `json:"remote_addr"` @@ -55,268 +42,46 @@ func (l *P2PConnected) EventName() string { return "p2p.connected" } -type P2PHandshaked struct { - RemoteCapabilities []string `json:"remote_capabilities"` - RemoteId string `json:"remote_id"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PHandshaked) EventName() string { - return "p2p.handshaked" -} - -type P2PDisconnected struct { - NumConnections int `json:"num_connections"` - RemoteId string `json:"remote_id"` - LogEvent -} - -func (l *P2PDisconnected) EventName() string { - return "p2p.disconnected" -} - -type P2PDisconnecting struct { - Reason string `json:"reason"` - RemoteId string `json:"remote_id"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PDisconnecting) EventName() string { - return "p2p.disconnecting" -} - -type P2PDisconnectingBadHandshake struct { - Reason string `json:"reason"` - RemoteId string `json:"remote_id"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PDisconnectingBadHandshake) EventName() string { - return "p2p.disconnecting.bad_handshake" -} - -type P2PDisconnectingBadProtocol struct { - Reason string `json:"reason"` - RemoteId string `json:"remote_id"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PDisconnectingBadProtocol) EventName() string { - return "p2p.disconnecting.bad_protocol" -} - -type P2PDisconnectingReputation struct { - Reason string `json:"reason"` - RemoteId string `json:"remote_id"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PDisconnectingReputation) EventName() string { - return "p2p.disconnecting.reputation" -} - -type P2PDisconnectingDHT struct { - Reason string `json:"reason"` - RemoteId string `json:"remote_id"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PDisconnectingDHT) EventName() string { - return "p2p.disconnecting.dht" -} - -type P2PEthDisconnectingBadBlock struct { - Reason string `json:"reason"` - RemoteId string `json:"remote_id"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PEthDisconnectingBadBlock) EventName() string { - return "p2p.eth.disconnecting.bad_block" -} - -type P2PEthDisconnectingBadTx struct { - Reason string `json:"reason"` - RemoteId string `json:"remote_id"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PEthDisconnectingBadTx) EventName() string { - return "p2p.eth.disconnecting.bad_tx" -} - -type EthNewBlockMined struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockHexRlp string `json:"block_hexrlp"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthNewBlockMined) EventName() string { - return "eth.newblock.mined" -} - -type EthNewBlockBroadcasted struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` +type EthMinerNewBlock struct { + BlockHash string `json:"block_hash"` + BlockNumber int `json:"block_number"` + ChainHeadHash string `json:"chain_head_hash"` + BlockPrevHash string `json:"block_prev_hash"` LogEvent } -func (l *EthNewBlockBroadcasted) EventName() string { - return "eth.newblock.broadcasted" +func (l *EthMinerNewBlock) EventName() string { + return "eth.miner.new_block" } -type EthNewBlockReceived struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` +type EthChainReceivedNewBlock struct { + BlockHash string `json:"block_hash"` + BlockNumber int `json:"block_number"` + ChainHeadHash string `json:"chain_head_hash"` + BlockPrevHash string `json:"block_prev_hash"` + RemoteId int `json:"remote_id"` LogEvent } -func (l *EthNewBlockReceived) EventName() string { - return "eth.newblock.received" +func (l *EthChainReceivedNewBlock) EventName() string { + return "eth.chain.received.new_block" } -type EthNewBlockIsKnown struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` +type EthChainNewHead struct { + BlockHash string `json:"block_hash"` + BlockNumber int `json:"block_number"` + ChainHeadHash string `json:"chain_head_hash"` + BlockPrevHash string `json:"block_prev_hash"` LogEvent } -func (l *EthNewBlockIsKnown) EventName() string { - return "eth.newblock.is_known" -} - -type EthNewBlockIsNew struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthNewBlockIsNew) EventName() string { - return "eth.newblock.is_new" -} - -type EthNewBlockMissingParent struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthNewBlockMissingParent) EventName() string { - return "eth.newblock.missing_parent" -} - -type EthNewBlockIsInvalid struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthNewBlockIsInvalid) EventName() string { - return "eth.newblock.is_invalid" -} - -type EthNewBlockChainIsOlder struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthNewBlockChainIsOlder) EventName() string { - return "eth.newblock.chain.is_older" -} - -type EthNewBlockChainIsCanonical struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthNewBlockChainIsCanonical) EventName() string { - return "eth.newblock.chain.is_cannonical" -} - -type EthNewBlockChainNotCanonical struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthNewBlockChainNotCanonical) EventName() string { - return "eth.newblock.chain.not_cannonical" -} - -type EthNewBlockChainSwitched struct { - BlockNumber int `json:"block_number"` - HeadHash string `json:"head_hash"` - OldHeadHash string `json:"old_head_hash"` - BlockHash string `json:"block_hash"` - BlockDifficulty int `json:"block_difficulty"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthNewBlockChainSwitched) EventName() string { - return "eth.newblock.chain.switched" -} - -type EthTxCreated struct { - TxHash string `json:"tx_hash"` - TxSender string `json:"tx_sender"` - TxAddress string `json:"tx_address"` - TxHexRLP string `json:"tx_hexrlp"` - TxNonce int `json:"tx_nonce"` - LogEvent -} - -func (l *EthTxCreated) EventName() string { - return "eth.tx.created" +func (l *EthChainNewHead) EventName() string { + return "eth.chain.new_head" } type EthTxReceived struct { - TxHash string `json:"tx_hash"` - TxAddress string `json:"tx_address"` - TxHexRLP string `json:"tx_hexrlp"` - RemoteId string `json:"remote_id"` - TxNonce int `json:"tx_nonce"` + TxHash string `json:"tx_hash"` + RemoteId string `json:"remote_id"` LogEvent } @@ -324,39 +89,271 @@ func (l *EthTxReceived) EventName() string { return "eth.tx.received" } -type EthTxBroadcasted struct { - TxHash string `json:"tx_hash"` - TxSender string `json:"tx_sender"` - TxAddress string `json:"tx_address"` - TxNonce int `json:"tx_nonce"` - LogEvent -} - -func (l *EthTxBroadcasted) EventName() string { - return "eth.tx.broadcasted" -} - -type EthTxValidated struct { - TxHash string `json:"tx_hash"` - TxSender string `json:"tx_sender"` - TxAddress string `json:"tx_address"` - TxNonce int `json:"tx_nonce"` - LogEvent -} - -func (l *EthTxValidated) EventName() string { - return "eth.tx.validated" -} - -type EthTxIsInvalid struct { - TxHash string `json:"tx_hash"` - TxSender string `json:"tx_sender"` - TxAddress string `json:"tx_address"` - Reason string `json:"reason"` - TxNonce int `json:"tx_nonce"` - LogEvent -} - -func (l *EthTxIsInvalid) EventName() string { - return "eth.tx.is_invalid" -} +// +// +// The types below are legacy and need to be converted to new format or deleted +// +// + +// type P2PConnecting struct { +// RemoteId string `json:"remote_id"` +// RemoteEndpoint string `json:"remote_endpoint"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PConnecting) EventName() string { +// return "p2p.connecting" +// } + +// type P2PHandshaked struct { +// RemoteCapabilities []string `json:"remote_capabilities"` +// RemoteId string `json:"remote_id"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PHandshaked) EventName() string { +// return "p2p.handshaked" +// } + +// type P2PDisconnected struct { +// NumConnections int `json:"num_connections"` +// RemoteId string `json:"remote_id"` +// LogEvent +// } + +// func (l *P2PDisconnected) EventName() string { +// return "p2p.disconnected" +// } + +// type P2PDisconnecting struct { +// Reason string `json:"reason"` +// RemoteId string `json:"remote_id"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PDisconnecting) EventName() string { +// return "p2p.disconnecting" +// } + +// type P2PDisconnectingBadHandshake struct { +// Reason string `json:"reason"` +// RemoteId string `json:"remote_id"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PDisconnectingBadHandshake) EventName() string { +// return "p2p.disconnecting.bad_handshake" +// } + +// type P2PDisconnectingBadProtocol struct { +// Reason string `json:"reason"` +// RemoteId string `json:"remote_id"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PDisconnectingBadProtocol) EventName() string { +// return "p2p.disconnecting.bad_protocol" +// } + +// type P2PDisconnectingReputation struct { +// Reason string `json:"reason"` +// RemoteId string `json:"remote_id"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PDisconnectingReputation) EventName() string { +// return "p2p.disconnecting.reputation" +// } + +// type P2PDisconnectingDHT struct { +// Reason string `json:"reason"` +// RemoteId string `json:"remote_id"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PDisconnectingDHT) EventName() string { +// return "p2p.disconnecting.dht" +// } + +// type P2PEthDisconnectingBadBlock struct { +// Reason string `json:"reason"` +// RemoteId string `json:"remote_id"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PEthDisconnectingBadBlock) EventName() string { +// return "p2p.eth.disconnecting.bad_block" +// } + +// type P2PEthDisconnectingBadTx struct { +// Reason string `json:"reason"` +// RemoteId string `json:"remote_id"` +// NumConnections int `json:"num_connections"` +// LogEvent +// } + +// func (l *P2PEthDisconnectingBadTx) EventName() string { +// return "p2p.eth.disconnecting.bad_tx" +// } + +// type EthNewBlockBroadcasted struct { +// BlockNumber int `json:"block_number"` +// HeadHash string `json:"head_hash"` +// BlockHash string `json:"block_hash"` +// BlockDifficulty int `json:"block_difficulty"` +// BlockPrevHash string `json:"block_prev_hash"` +// LogEvent +// } + +// func (l *EthNewBlockBroadcasted) EventName() string { +// return "eth.newblock.broadcasted" +// } + +// type EthNewBlockIsKnown struct { +// BlockNumber int `json:"block_number"` +// HeadHash string `json:"head_hash"` +// BlockHash string `json:"block_hash"` +// BlockDifficulty int `json:"block_difficulty"` +// BlockPrevHash string `json:"block_prev_hash"` +// LogEvent +// } + +// func (l *EthNewBlockIsKnown) EventName() string { +// return "eth.newblock.is_known" +// } + +// type EthNewBlockIsNew struct { +// BlockNumber int `json:"block_number"` +// HeadHash string `json:"head_hash"` +// BlockHash string `json:"block_hash"` +// BlockDifficulty int `json:"block_difficulty"` +// BlockPrevHash string `json:"block_prev_hash"` +// LogEvent +// } + +// func (l *EthNewBlockIsNew) EventName() string { +// return "eth.newblock.is_new" +// } + +// type EthNewBlockMissingParent struct { +// BlockNumber int `json:"block_number"` +// HeadHash string `json:"head_hash"` +// BlockHash string `json:"block_hash"` +// BlockDifficulty int `json:"block_difficulty"` +// BlockPrevHash string `json:"block_prev_hash"` +// LogEvent +// } + +// func (l *EthNewBlockMissingParent) EventName() string { +// return "eth.newblock.missing_parent" +// } + +// type EthNewBlockIsInvalid struct { +// BlockNumber int `json:"block_number"` +// HeadHash string `json:"head_hash"` +// BlockHash string `json:"block_hash"` +// BlockDifficulty int `json:"block_difficulty"` +// BlockPrevHash string `json:"block_prev_hash"` +// LogEvent +// } + +// func (l *EthNewBlockIsInvalid) EventName() string { +// return "eth.newblock.is_invalid" +// } + +// type EthNewBlockChainIsOlder struct { +// BlockNumber int `json:"block_number"` +// HeadHash string `json:"head_hash"` +// BlockHash string `json:"block_hash"` +// BlockDifficulty int `json:"block_difficulty"` +// BlockPrevHash string `json:"block_prev_hash"` +// LogEvent +// } + +// func (l *EthNewBlockChainIsOlder) EventName() string { +// return "eth.newblock.chain.is_older" +// } + +// type EthNewBlockChainIsCanonical struct { +// BlockNumber int `json:"block_number"` +// HeadHash string `json:"head_hash"` +// BlockHash string `json:"block_hash"` +// BlockDifficulty int `json:"block_difficulty"` +// BlockPrevHash string `json:"block_prev_hash"` +// LogEvent +// } + +// func (l *EthNewBlockChainIsCanonical) EventName() string { +// return "eth.newblock.chain.is_cannonical" +// } + +// type EthNewBlockChainNotCanonical struct { +// BlockNumber int `json:"block_number"` +// HeadHash string `json:"head_hash"` +// BlockHash string `json:"block_hash"` +// BlockDifficulty int `json:"block_difficulty"` +// BlockPrevHash string `json:"block_prev_hash"` +// LogEvent +// } + +// func (l *EthNewBlockChainNotCanonical) EventName() string { +// return "eth.newblock.chain.not_cannonical" +// } + +// type EthTxCreated struct { +// TxHash string `json:"tx_hash"` +// TxSender string `json:"tx_sender"` +// TxAddress string `json:"tx_address"` +// TxHexRLP string `json:"tx_hexrlp"` +// TxNonce int `json:"tx_nonce"` +// LogEvent +// } + +// func (l *EthTxCreated) EventName() string { +// return "eth.tx.created" +// } + +// type EthTxBroadcasted struct { +// TxHash string `json:"tx_hash"` +// TxSender string `json:"tx_sender"` +// TxAddress string `json:"tx_address"` +// TxNonce int `json:"tx_nonce"` +// LogEvent +// } + +// func (l *EthTxBroadcasted) EventName() string { +// return "eth.tx.broadcasted" +// } + +// type EthTxValidated struct { +// TxHash string `json:"tx_hash"` +// TxSender string `json:"tx_sender"` +// TxAddress string `json:"tx_address"` +// TxNonce int `json:"tx_nonce"` +// LogEvent +// } + +// func (l *EthTxValidated) EventName() string { +// return "eth.tx.validated" +// } + +// type EthTxIsInvalid struct { +// TxHash string `json:"tx_hash"` +// TxSender string `json:"tx_sender"` +// TxAddress string `json:"tx_address"` +// Reason string `json:"reason"` +// TxNonce int `json:"tx_nonce"` +// LogEvent +// } + +// func (l *EthTxIsInvalid) EventName() string { +// return "eth.tx.is_invalid" +// } From 07bdba687f4971641c4dadc526c634dfbe4177d8 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Wed, 18 Feb 2015 10:52:36 +0100 Subject: [PATCH 04/78] Re-add LogFormat to Config --- cmd/ethereum/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 0dba462be3..d4a57ee489 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -67,6 +67,7 @@ func main() { DataDir: Datadir, LogFile: LogFile, LogLevel: LogLevel, + LogFormat: LogFormat, MaxPeers: MaxPeer, Port: OutboundPort, NAT: NAT, From 05b1ec008b771d9856e83a6269a5267eb18e1f51 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Feb 2015 11:42:01 +0100 Subject: [PATCH 05/78] Disabled ability to disable whisper. Closes #334 --- cmd/ethereum/flags.go | 2 +- cmd/ethereum/main.go | 2 +- cmd/mist/main.go | 1 + eth/backend.go | 6 +++++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/ethereum/flags.go b/cmd/ethereum/flags.go index 1e6869a694..577bee4426 100644 --- a/cmd/ethereum/flags.go +++ b/cmd/ethereum/flags.go @@ -132,7 +132,7 @@ func Init() { natstr = flag.String("nat", "any", "port mapping mechanism (any|none|upnp|pmp|extip:)") ) flag.BoolVar(&Dial, "dial", true, "dial out connections (default on)") - flag.BoolVar(&SHH, "shh", true, "run whisper protocol (default on)") + //flag.BoolVar(&SHH, "shh", true, "run whisper protocol (default on)") flag.StringVar(&OutboundPort, "port", "30303", "listening port") flag.StringVar(&BootNodes, "bootnodes", "", "space-separated node URLs for discovery bootstrap") diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 0dba462be3..1ffd4b6e98 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -71,7 +71,7 @@ func main() { Port: OutboundPort, NAT: NAT, KeyRing: KeyRing, - Shh: SHH, + Shh: true, Dial: Dial, BootNodes: BootNodes, NodeKey: NodeKey, diff --git a/cmd/mist/main.go b/cmd/mist/main.go index 32222fbef5..14f561e991 100644 --- a/cmd/mist/main.go +++ b/cmd/mist/main.go @@ -60,6 +60,7 @@ func run() error { MaxPeers: MaxPeer, Port: OutboundPort, NAT: NAT, + Shh: true, BootNodes: BootNodes, NodeKey: NodeKey, KeyRing: KeyRing, diff --git a/eth/backend.go b/eth/backend.go index 690c7136d2..d109ab98e6 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -160,7 +160,11 @@ func New(config *Config) (*Ethereum, error) { eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify) ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool) - protocols := []p2p.Protocol{ethProto, eth.whisper.Protocol()} + 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 { From be90ad89a89502ef3d2c0375d267b667618f5e7c Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Feb 2015 12:01:20 +0100 Subject: [PATCH 06/78] Disable turbo --- pow/ezp/pow.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pow/ezp/pow.go b/pow/ezp/pow.go index f4a8b80e5e..540381243f 100644 --- a/pow/ezp/pow.go +++ b/pow/ezp/pow.go @@ -21,7 +21,7 @@ type EasyPow struct { } func New() *EasyPow { - return &EasyPow{turbo: true} + return &EasyPow{turbo: false} } func (pow *EasyPow) GetHashrate() int64 { From 655e94259765b02454df93205a30a271103de5a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Feb 2015 13:14:21 +0100 Subject: [PATCH 07/78] Added GetBlock GetUncle with OOB guard --- core/block_processor.go | 6 +++++- core/block_processor_test.go | 34 ++++++++++++++++++++++++++++++++++ core/chain_manager.go | 16 ++++++++-------- core/types/block.go | 12 ++++++++++++ 4 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 core/block_processor_test.go diff --git a/core/block_processor.go b/core/block_processor.go index 893c586dd4..b4449100f3 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -250,7 +250,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error { } if block.Time() > time.Now().Unix() { - return fmt.Errorf("block time is in the future") + return BlockFutureErr + } + + if new(big.Int).Sub(block.Number(), parent.Number()).Cmp(big.NewInt(1)) != 0 { + return BlockNumberErr } // Verify the nonce of the block. Return an error if it's not valid diff --git a/core/block_processor_test.go b/core/block_processor_test.go new file mode 100644 index 0000000000..35aeaa714a --- /dev/null +++ b/core/block_processor_test.go @@ -0,0 +1,34 @@ +package core + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" +) + +func proc() (*BlockProcessor, *ChainManager) { + db, _ := ethdb.NewMemDatabase() + var mux event.TypeMux + + chainMan := NewChainManager(db, &mux) + return NewBlockProcessor(db, nil, chainMan, &mux), chainMan +} + +func TestNumber(t *testing.T) { + bp, chain := proc() + block1 := chain.NewBlock(nil) + block1.Header().Number = big.NewInt(3) + + err := bp.ValidateBlock(block1, chain.Genesis()) + if err != BlockNumberErr { + t.Errorf("expected block number error") + } + + block1 = chain.NewBlock(nil) + err = bp.ValidateBlock(block1, chain.Genesis()) + if err == BlockNumberErr { + t.Errorf("didn't expect block number error") + } +} diff --git a/core/chain_manager.go b/core/chain_manager.go index 22d54be03e..2862820644 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -87,6 +87,14 @@ type ChainManager struct { transState *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() + + return bc +} + func (self *ChainManager) Td() *big.Int { self.mu.RLock() defer self.mu.RUnlock() @@ -108,14 +116,6 @@ func (self *ChainManager) CurrentBlock() *types.Block { return self.currentBlock } -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() - - return bc -} - func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { self.mu.RLock() defer self.mu.RUnlock() diff --git a/core/types/block.go b/core/types/block.go index fa28f5cc75..d57de13117 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -185,6 +185,18 @@ func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } func (self *Block) Root() []byte { return self.header.Root } func (self *Block) SetRoot(root []byte) { self.header.Root = root } func (self *Block) Size() ethutil.StorageSize { return ethutil.StorageSize(len(ethutil.Encode(self))) } +func (self *Block) GetTransaction(i int) *Transaction { + if len(self.transactions) > i { + return self.transactions[i] + } + return nil +} +func (self *Block) GetUncle(i int) *Header { + if len(self.uncles) > i { + return self.uncles[i] + } + return nil +} // Implement pow.Block func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } From ee9df32dba5091069cbdad8d00dc15738d676d5b Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Feb 2015 16:08:51 +0100 Subject: [PATCH 08/78] Added errors --- core/error.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/error.go b/core/error.go index 11d8c16537..6af48ac2de 100644 --- a/core/error.go +++ b/core/error.go @@ -1,10 +1,16 @@ package core import ( + "errors" "fmt" "math/big" ) +var ( + BlockNumberErr = errors.New("block number invalid") + BlockFutureErr = errors.New("block time is in the future") +) + // Parent error. In case a parent is unknown this error will be thrown // by the block manager type ParentErr struct { From 487c5cc294d4c0506e50a026737be7f4cc94436f Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Feb 2015 17:18:07 +0100 Subject: [PATCH 09/78] Added WIP number package --- ethutil/number/int.go | 181 ++++++++++++++++++++++++++++++++++++ ethutil/number/uint_test.go | 92 ++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 ethutil/number/int.go create mode 100644 ethutil/number/uint_test.go diff --git a/ethutil/number/int.go b/ethutil/number/int.go new file mode 100644 index 0000000000..9a41fe3e5d --- /dev/null +++ b/ethutil/number/int.go @@ -0,0 +1,181 @@ +package number + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/ethutil" +) + +var tt256 = new(big.Int).Lsh(big.NewInt(1), 256) +var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) +var tt255 = new(big.Int).Lsh(big.NewInt(1), 255) + +func limitUnsigned256(x *Number) *Number { + x.num.And(x.num, tt256m1) + return x +} + +func limitSigned256(x *Number) *Number { + if x.num.Cmp(tt255) < 0 { + return x + } else { + x.num.Sub(x.num, tt256) + return x + } +} + +// Number function +type Initialiser func(n int64) *Number + +// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations +// to give "fake" bounded integers. New types of Number can be created through NewInitialiser returning a lambda +// with the new Initialiser. +type Number struct { + num *big.Int + limit func(n *Number) *Number +} + +// Returns a new initialiser for a new *Number without having to expose certain fields +func NewInitialiser(limiter func(*Number) *Number) Initialiser { + return func(n int64) *Number { + return &Number{big.NewInt(n), limiter} + } +} + +// Return a Number with a UNSIGNED limiter up to 256 bits +func Uint256(n int64) *Number { + return &Number{big.NewInt(n), limitUnsigned256} +} + +// Return a Number with a SIGNED limiter up to 256 bits +func Int256(n int64) *Number { + return &Number{big.NewInt(n), limitSigned256} +} + +// Returns a Number with a SIGNED unlimited size +func Big(n int64) *Number { + return &Number{big.NewInt(n), func(x *Number) *Number { return x }} +} + +// Sets i to sum of x+y +func (i *Number) Add(x, y *Number) *Number { + i.num.Add(x.num, y.num) + return i.limit(i) +} + +// Sets i to difference of x-y +func (i *Number) Sub(x, y *Number) *Number { + i.num.Sub(x.num, y.num) + return i.limit(i) +} + +// Sets i to product of x*y +func (i *Number) Mul(x, y *Number) *Number { + i.num.Mul(x.num, y.num) + return i.limit(i) +} + +// Sets i to the quotient prodject of x/y +func (i *Number) Div(x, y *Number) *Number { + i.num.Div(x.num, y.num) + return i.limit(i) +} + +// Sets i to x % y +func (i *Number) Mod(x, y *Number) *Number { + i.num.Mod(x.num, y.num) + return i.limit(i) +} + +// Sets i to x << s +func (i *Number) Lsh(x *Number, s uint) *Number { + i.num.Lsh(x.num, s) + return i.limit(i) +} + +// Sets i to x^y +func (i *Number) Pow(x, y *Number) *Number { + i.num.Exp(x.num, y.num, big.NewInt(0)) + return i.limit(i) +} + +// Setters + +// Set x to i +func (i *Number) Set(x *Number) *Number { + i.num.Set(x.num) + return i.limit(i) +} + +// Set x bytes to i +func (i *Number) SetBytes(x []byte) *Number { + i.num.SetBytes(x) + return i.limit(i) +} + +// Cmp compares x and y and returns: +// +// -1 if x < y +// 0 if x == y +// +1 if x > y +func (i *Number) Cmp(x *Number) int { + return i.num.Cmp(x.num) +} + +// Getters + +// Returns the string representation of i +func (i *Number) String() string { + return i.num.String() +} + +// Returns the byte representation of i +func (i *Number) Bytes() []byte { + return i.num.Bytes() +} + +// Uint64 returns the Uint64 representation of x. If x cannot be represented in an int64, the result is undefined. +func (i *Number) Uint64() uint64 { + return i.num.Uint64() +} + +// Int64 returns the int64 representation of x. If x cannot be represented in an int64, the result is undefined. +func (i *Number) Int64() int64 { + return i.num.Int64() +} + +// Returns the signed version of i +func (i *Number) Int256() *Number { + return Int(0).Set(i) +} + +// Returns the unsigned version of i +func (i *Number) Uint256() *Number { + return Uint(0).Set(i) +} + +// Returns the index of the first bit that's set to 1 +func (i *Number) FirstBitSet() int { + for j := 0; j < i.num.BitLen(); j++ { + if i.num.Bit(j) > 0 { + return j + } + } + + return i.num.BitLen() +} + +// Variables + +var ( + Zero = Uint(0) + One = Uint(1) + Two = Uint(2) + MaxUint256 = Uint(0).SetBytes(ethutil.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) + + MinOne = Int(-1) + + // "typedefs" + Uint = Uint256 + Int = Int256 +) diff --git a/ethutil/number/uint_test.go b/ethutil/number/uint_test.go new file mode 100644 index 0000000000..c429894653 --- /dev/null +++ b/ethutil/number/uint_test.go @@ -0,0 +1,92 @@ +package number + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/ethutil" +) + +func TestSet(t *testing.T) { + a := Uint(0) + b := Uint(10) + a.Set(b) + if a.num.Cmp(b.num) != 0 { + t.Error("didn't compare", a, b) + } + + c := Uint(0).SetBytes(ethutil.Hex2Bytes("0a")) + if c.num.Cmp(big.NewInt(10)) != 0 { + t.Error("c set bytes failed.") + } +} + +func TestInitialiser(t *testing.T) { + check := false + init := NewInitialiser(func(x *Number) *Number { + check = true + return x + }) + a := init(0).Add(init(1), init(2)) + if a.Cmp(init(3)) != 0 { + t.Error("expected 3. got", a) + } + if !check { + t.Error("expected limiter to be called") + } +} + +func TestGet(t *testing.T) { + a := Uint(10) + if a.Uint64() != 10 { + t.Error("expected to get 10. got", a.Uint64()) + } + + a = Uint(10) + if a.Int64() != 10 { + t.Error("expected to get 10. got", a.Int64()) + } +} + +func TestCmp(t *testing.T) { + a := Uint(10) + b := Uint(10) + c := Uint(11) + + if a.Cmp(b) != 0 { + t.Error("a b == 0 failed", a, b) + } + + if a.Cmp(c) >= 0 { + t.Error("a c < 0 failed", a, c) + } + + if c.Cmp(b) <= 0 { + t.Error("c b > 0 failed", c, b) + } +} + +func TestMaxArith(t *testing.T) { + a := Uint(0).Add(MaxUint256, One) + if a.Cmp(Zero) != 0 { + t.Error("expected max256 + 1 = 0 got", a) + } + + a = Uint(0).Sub(Uint(0), One) + if a.Cmp(MaxUint256) != 0 { + t.Error("expected 0 - 1 = max256 got", a) + } + + a = Int(0).Sub(Int(0), One) + if a.Cmp(MinOne) != 0 { + t.Error("expected 0 - 1 = -1 got", a) + } +} + +func TestConversion(t *testing.T) { + a := Int(-1) + b := a.Uint256() + if b.Cmp(MaxUint256) != 0 { + t.Error("expected -1 => unsigned to return max. got", b) + } +} From 5aff8bfb5918e53ba2590b25e6c17e1875870f6a Mon Sep 17 00:00:00 2001 From: Maran Date: Thu, 19 Feb 2015 10:38:36 +0100 Subject: [PATCH 10/78] Implement command line argument to set the amount of agents created by the miner Defaults to the amount of cores available on the CPU --- cmd/mist/flags.go | 3 +++ cmd/mist/main.go | 27 ++++++++++++++------------- cmd/utils/cmd.go | 2 +- eth/backend.go | 4 +++- miner/miner.go | 4 ++-- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/cmd/mist/flags.go b/cmd/mist/flags.go index eb280f71bd..d9487de9e0 100644 --- a/cmd/mist/flags.go +++ b/cmd/mist/flags.go @@ -63,6 +63,7 @@ var ( DebugFile string LogLevel int VmType int + MinerThreads int ) // flags specific to gui client @@ -137,6 +138,8 @@ func Init() { flag.StringVar(&BootNodes, "bootnodes", "", "space-separated node URLs for discovery bootstrap") flag.IntVar(&MaxPeer, "maxpeer", 30, "maximum desired peers") + flag.IntVar(&MinerThreads, "minerthreads", runtime.NumCPU(), "number of miner threads") + flag.Parse() var err error diff --git a/cmd/mist/main.go b/cmd/mist/main.go index 14f561e991..d41aa34bf3 100644 --- a/cmd/mist/main.go +++ b/cmd/mist/main.go @@ -52,19 +52,20 @@ func run() error { config := utils.InitConfig(VmType, ConfigFile, Datadir, "ETH") ethereum, err := eth.New(ð.Config{ - Name: p2p.MakeName(ClientIdentifier, Version), - KeyStore: KeyStore, - DataDir: Datadir, - LogFile: LogFile, - LogLevel: LogLevel, - MaxPeers: MaxPeer, - Port: OutboundPort, - NAT: NAT, - Shh: true, - BootNodes: BootNodes, - NodeKey: NodeKey, - KeyRing: KeyRing, - Dial: true, + Name: p2p.MakeName(ClientIdentifier, Version), + KeyStore: KeyStore, + DataDir: Datadir, + LogFile: LogFile, + LogLevel: LogLevel, + MaxPeers: MaxPeer, + Port: OutboundPort, + NAT: NAT, + Shh: true, + BootNodes: BootNodes, + NodeKey: NodeKey, + KeyRing: KeyRing, + Dial: true, + MinerThreads: MinerThreads, }) if err != nil { mainlogger.Fatalln(err) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index ecb847fc38..d252f3ab24 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -225,7 +225,7 @@ func StartMining(ethereum *eth.Ethereum) bool { go func() { clilogger.Infoln("Start mining") if gminer == nil { - gminer = miner.New(addr, ethereum) + gminer = miner.New(addr, ethereum, 4) } gminer.Start() }() diff --git a/eth/backend.go b/eth/backend.go index d109ab98e6..05d84cae8d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -53,6 +53,8 @@ type Config struct { Shh bool Dial bool + MinerThreads int + KeyManager *crypto.KeyManager } @@ -153,7 +155,7 @@ func New(config *Config) (*Ethereum, error) { eth.blockProcessor = core.NewBlockProcessor(db, eth.txPool, eth.chainManager, eth.EventMux()) eth.chainManager.SetProcessor(eth.blockProcessor) eth.whisper = whisper.New() - eth.miner = miner.New(keyManager.Address(), eth) + eth.miner = miner.New(keyManager.Address(), eth, config.MinerThreads) hasBlock := eth.chainManager.HasBlock insertChain := eth.chainManager.InsertChain diff --git a/miner/miner.go b/miner/miner.go index 27afcf684e..0cc2361c89 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -20,13 +20,13 @@ type Miner struct { mining bool } -func New(coinbase []byte, eth core.Backend) *Miner { +func New(coinbase []byte, eth core.Backend, minerThreads int) *Miner { miner := &Miner{ Coinbase: coinbase, worker: newWorker(coinbase, eth), } - for i := 0; i < 4; i++ { + for i := 0; i < minerThreads; i++ { miner.worker.register(NewCpuMiner(i, ezp.New())) } From fdecc11128596eadc00e7a7d81b856d844396c37 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 11:09:46 +0100 Subject: [PATCH 11/78] Temp fix for #342 --- vm/vm.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vm/vm.go b/vm/vm.go index 29e1ade543..5ec507ddc6 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -266,7 +266,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I base.Sub(Pow256, stack.Pop()).Sub(base, ethutil.Big1) // Not needed - //base = U256(base) + base = U256(base) stack.Push(base) case LT: @@ -532,7 +532,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I case NUMBER: number := self.env.BlockNumber() - stack.Push(number) + stack.Push(U256(number)) self.Printf(" => 0x%x", number.Bytes()) case DIFFICULTY: @@ -676,6 +676,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I gas := stack.Pop() // Pop gas and value of the stack. value, addr := stack.Popn() + value = U256(value) // Pop input size and offset inSize, inOffset := stack.Popn() // Pop return size and offset From 03b8c6841be08f19db0f98cea6d0a6f4fd64736f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 11:49:58 +0100 Subject: [PATCH 12/78] Topics => Topic. Closes #343 --- rpc/args.go | 2 +- rpc/message.go | 17 +---------------- rpc/packages.go | 10 +++++----- 3 files changed, 7 insertions(+), 22 deletions(-) diff --git a/rpc/args.go b/rpc/args.go index 429b385d54..f730819fd9 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -289,7 +289,7 @@ type WhisperMessageArgs struct { Payload string To string From string - Topics []string + Topic []string Priority uint32 Ttl uint32 } diff --git a/rpc/message.go b/rpc/message.go index b5b852f544..d96c35d7e6 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -231,21 +231,6 @@ func (req *RpcRequest) ToFilterStringArgs() (string, error) { return args, nil } -func (req *RpcRequest) ToFilterChangedArgs() (int, error) { - if len(req.Params) < 1 { - return 0, NewErrorResponse(ErrorArguments) - } - - var id int - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(&id) - if err != nil { - return 0, NewErrorResponse(ErrorDecodeArgs) - } - rpclogger.DebugDetailf("%T %v", id, id) - return id, nil -} - func (req *RpcRequest) ToDbPutArgs() (*DbArgs, error) { if len(req.Params) < 3 { return nil, NewErrorResponse(ErrorArguments) @@ -301,7 +286,7 @@ func (req *RpcRequest) ToWhisperFilterArgs() (*xeth.Options, error) { return &args, nil } -func (req *RpcRequest) ToWhisperIdArgs() (int, error) { +func (req *RpcRequest) ToIdArgs() (int, error) { if len(req.Params) < 1 { return 0, NewErrorResponse(ErrorArguments) } diff --git a/rpc/packages.go b/rpc/packages.go index 8aa604aa55..7044d9d127 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -349,7 +349,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.Topics, 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 } @@ -445,13 +445,13 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.NewFilterString(args, reply) case "eth_changed": - args, err := req.ToFilterChangedArgs() + args, err := req.ToIdArgs() if err != nil { return err } return p.FilterChanged(args, reply) case "eth_filterLogs": - args, err := req.ToFilterChangedArgs() + args, err := req.ToIdArgs() if err != nil { return err } @@ -504,7 +504,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.NewWhisperFilter(args, reply) case "shh_changed": - args, err := req.ToWhisperIdArgs() + args, err := req.ToIdArgs() if err != nil { return err } @@ -522,7 +522,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.HasWhisperIdentity(args, reply) case "shh_getMessages": - args, err := req.ToWhisperIdArgs() + args, err := req.ToIdArgs() if err != nil { return err } From 0057bb4ef6d55b5d580a4e0421526a477ef93de9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 11:51:38 +0100 Subject: [PATCH 13/78] WIP QT Clipboard --- cmd/mist/assets/qml/main.qml | 1 + cmd/mist/gui.go | 1 + rpc/util.go | 6 +++--- ui/qt/clipboard/capi.hpp | 11 +++++++++++ ui/qt/clipboard/clipboard.cpp | 20 ++++++++++++++++++++ ui/qt/clipboard/clipboard.go | 15 +++++++++++++++ ui/qt/clipboard/clipboard.hpp | 23 +++++++++++++++++++++++ xeth/types.go | 2 +- 8 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 ui/qt/clipboard/capi.hpp create mode 100644 ui/qt/clipboard/clipboard.cpp create mode 100644 ui/qt/clipboard/clipboard.go create mode 100644 ui/qt/clipboard/clipboard.hpp diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index f9bfd9b8d2..5f7f05d835 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -246,6 +246,7 @@ ApplicationWindow { } } } + } property var blockModel: ListModel { diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index c9419473ce..1e3efd269f 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -131,6 +131,7 @@ func (gui *Gui) Start(assetPath string) { context.SetVar("gui", gui) context.SetVar("eth", gui.uiLib) context.SetVar("shh", gui.whisper) + //clipboard.SetQMLClipboard(context) win, err := gui.showWallet(context) if err != nil { diff --git a/rpc/util.go b/rpc/util.go index 679d83754d..366e315ac2 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -80,7 +80,7 @@ type RpcServer interface { type Log struct { Address string `json:"address"` - Topics []string `json:"topics"` + Topic []string `json:"topics"` Data string `json:"data"` } @@ -89,11 +89,11 @@ func toLogs(logs state.Logs) (ls []Log) { for i, log := range logs { var l Log - l.Topics = make([]string, len(log.Topics())) + l.Topic = make([]string, len(log.Topics())) l.Address = toHex(log.Address()) l.Data = toHex(log.Data()) for j, topic := range log.Topics() { - l.Topics[j] = toHex(topic) + l.Topic[j] = toHex(topic) } ls[i] = l } diff --git a/ui/qt/clipboard/capi.hpp b/ui/qt/clipboard/capi.hpp new file mode 100644 index 0000000000..2026134691 --- /dev/null +++ b/ui/qt/clipboard/capi.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "clipboard.hpp" + +typedef void Clipboard_; + +Clipboard_ *initClipboard() +{ + Clipboard *clipboard = new(Clipboard); + return static_cast(clipboard); +} diff --git a/ui/qt/clipboard/clipboard.cpp b/ui/qt/clipboard/clipboard.cpp new file mode 100644 index 0000000000..192aa7a2b9 --- /dev/null +++ b/ui/qt/clipboard/clipboard.cpp @@ -0,0 +1,20 @@ +#include "clipboard.h" + +#include + +Clipboard::Clipboard() +{ + connect(QApplication::clipboard(), &QClipboard::dataChanged, [this] { emit clipboardChanged();}); +} + +QString Clipboard::get() const +{ + QClipboard *clipboard = QApplication::clipboard(); + return clipboard->text(); +} + +void Clipboard::toClipboard(QString _text) +{ + QClipboard *clipboard = QApplicationion::clipboard(); + clipboard->setText(_text); +} diff --git a/ui/qt/clipboard/clipboard.go b/ui/qt/clipboard/clipboard.go new file mode 100644 index 0000000000..064ee954d0 --- /dev/null +++ b/ui/qt/clipboard/clipboard.go @@ -0,0 +1,15 @@ +package clipboard + +// #cgo CPPFLAGS: -I./ +// #cgo CXXFLAGS: -std=c++0x -pedantic-errors -Wall -fno-strict-aliasing +// #cgo LDFLAGS: -lstdc++ +// #cgo pkg-config: Qt5Quick +// +// #include "capi.hpp" +import "C" + +import "github.com/obscuren/qml" + +func SetQMLClipboard(context *qml.Context) { + context.SetVar("clipboard", (unsafe.Pointer)(C.initClipboard())) +} diff --git a/ui/qt/clipboard/clipboard.hpp b/ui/qt/clipboard/clipboard.hpp new file mode 100644 index 0000000000..1aa213ceb1 --- /dev/null +++ b/ui/qt/clipboard/clipboard.hpp @@ -0,0 +1,23 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +class Clipboard : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString get READ get WRITE toClipboard NOTIFY clipboardChanged) +public: + Clipboard(); + virtual ~Clipboard(){} + + Q_INVOKABLE void toClipboard(QString _text); + +signals: + void clipboardChanged(); +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/xeth/types.go b/xeth/types.go index a903fccbbf..5b2d160180 100644 --- a/xeth/types.go +++ b/xeth/types.go @@ -150,7 +150,7 @@ type Transaction struct { func NewTx(tx *types.Transaction) *Transaction { hash := toHex(tx.Hash()) receiver := toHex(tx.To()) - if receiver == "0000000000000000000000000000000000000000" { + if len(receiver) == 0 { receiver = toHex(core.AddressFromMessage(tx)) } sender := toHex(tx.From()) From dba4f3122e83a66edc1fa089c5d69f789b07a6b3 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 19 Feb 2015 13:21:37 +0100 Subject: [PATCH 14/78] Added uninstall filter methods --- rpc/message.go | 15 +++++++++++++++ rpc/packages.go | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/rpc/message.go b/rpc/message.go index b5b852f544..524d7fc848 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -231,6 +231,21 @@ func (req *RpcRequest) ToFilterStringArgs() (string, error) { return args, nil } +func (req *RpcRequest) ToUninstallFilterArgs() (int, error) { + if len(req.Params) < 1 { + return 0, NewErrorResponse(ErrorArguments) + } + + var args int + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return 0, NewErrorResponse(ErrorDecodeArgs) + } + + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToFilterChangedArgs() (int, error) { if len(req.Params) < 1 { return 0, NewErrorResponse(ErrorArguments) diff --git a/rpc/packages.go b/rpc/packages.go index 8aa604aa55..216321dba5 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -105,6 +105,13 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro return nil } +func (self *EthereumApi) UninstallFilter(id int, reply *interface{}) error { + delete(self.logs, id) + self.filterManager.UninstallFilter(id) + *reply = true + return nil +} + func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error { var id int filter := core.NewFilter(self.xeth.Backend()) @@ -444,6 +451,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.NewFilterString(args, reply) + case "eth_uninstallFilter": + args, err := req.ToUninstallFilterArgs() + if err != nil { + return err + } + return p.UninstallFilter(args, reply) case "eth_changed": args, err := req.ToFilterChangedArgs() if err != nil { From c14071df9da4ab3f5b372293e87184af9b91c09e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 13:34:27 +0100 Subject: [PATCH 15/78] Reset storage cache after sync --- state/state_object.go | 1 + 1 file changed, 1 insertion(+) diff --git a/state/state_object.go b/state/state_object.go index 0c157403ca..eaa91c7133 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -152,6 +152,7 @@ func (self *StateObject) Sync() { self.setAddr([]byte(key), value) } + self.storage = make(Storage) } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { From 73f94f37559ca0c8739c7dddeaf46d36827fdf30 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Feb 2015 01:52:03 +0100 Subject: [PATCH 16/78] p2p: disable encryption handshake The diff is a bit bigger than expected because the protocol handshake logic has moved out of Peer. This is necessary because the protocol handshake will have custom framing in the final protocol. --- p2p/{crypto.go => handshake.go} | 137 +++++++++---- p2p/{crypto_test.go => handshake_test.go} | 63 +++++- p2p/message.go | 2 +- p2p/peer.go | 229 ++++++---------------- p2p/peer_test.go | 105 ++-------- p2p/server.go | 38 ++-- p2p/server_test.go | 12 +- 7 files changed, 273 insertions(+), 313 deletions(-) rename p2p/{crypto.go => handshake.go} (76%) rename p2p/{crypto_test.go => handshake_test.go} (74%) diff --git a/p2p/crypto.go b/p2p/handshake.go similarity index 76% rename from p2p/crypto.go rename to p2p/handshake.go index 7e4b437128..614711eafc 100644 --- a/p2p/crypto.go +++ b/p2p/handshake.go @@ -1,21 +1,20 @@ package p2p import ( - // "binary" "crypto/ecdsa" "crypto/rand" + "errors" "fmt" "io" + "net" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" - ethlogger "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/rlp" ) -var clogger = ethlogger.NewLogger("CRYPTOID") - const ( sskLen = 16 // ecies.MaxSharedKeyLength(pubKey) / 2 sigLen = 65 // elliptic S256 @@ -30,26 +29,76 @@ const ( rHSLen = authRespLen + eciesBytes // size of the final ECIES payload sent as receiver's handshake ) -type hexkey []byte +type conn struct { + *frameRW + *protoHandshake +} -func (self hexkey) String() string { - return fmt.Sprintf("(%d) %x", len(self), []byte(self)) +func newConn(fd net.Conn, hs *protoHandshake) *conn { + return &conn{newFrameRW(fd, msgWriteTimeout), hs} } -func encHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, dial *discover.Node) ( - remoteID discover.NodeID, - sessionToken []byte, - err error, -) { +// encHandshake represents information about the remote end +// of a connection that is negotiated during the encryption handshake. +type encHandshake struct { + ID discover.NodeID + IngressMAC []byte + EgressMAC []byte + Token []byte +} + +// protoHandshake is the RLP structure of the protocol handshake. +type protoHandshake struct { + Version uint64 + Name string + Caps []Cap + ListenPort uint64 + ID discover.NodeID +} + +// setupConn starts a protocol session on the given connection. +// It runs the encryption handshake and the protocol handshake. +// If dial is non-nil, the connection the local node is the initiator. +func setupConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node) (*conn, error) { if dial == nil { - var remotePubkey []byte - sessionToken, remotePubkey, err = inboundEncHandshake(conn, prv, nil) - copy(remoteID[:], remotePubkey) + return setupInboundConn(fd, prv, our) } else { - remoteID = dial.ID - sessionToken, err = outboundEncHandshake(conn, prv, remoteID[:], nil) + return setupOutboundConn(fd, prv, our, dial) + } +} + +func setupInboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake) (*conn, error) { + // var remotePubkey []byte + // sessionToken, remotePubkey, err = inboundEncHandshake(fd, prv, nil) + // copy(remoteID[:], remotePubkey) + + rw := newFrameRW(fd, msgWriteTimeout) + rhs, err := readProtocolHandshake(rw, our) + if err != nil { + return nil, err + } + if err := writeProtocolHandshake(rw, our); err != nil { + return nil, fmt.Errorf("protocol write error: %v", err) + } + return &conn{rw, rhs}, nil +} + +func setupOutboundConn(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node) (*conn, error) { + // remoteID = dial.ID + // sessionToken, err = outboundEncHandshake(fd, prv, remoteID[:], nil) + + rw := newFrameRW(fd, msgWriteTimeout) + if err := writeProtocolHandshake(rw, our); err != nil { + return nil, fmt.Errorf("protocol write error: %v", err) } - return remoteID, sessionToken, err + rhs, err := readProtocolHandshake(rw, our) + if err != nil { + return nil, fmt.Errorf("protocol handshake read error: %v", err) + } + if rhs.ID != dial.ID { + return nil, errors.New("dialed node id mismatch") + } + return &conn{rw, rhs}, nil } // outboundEncHandshake negotiates a session token on conn. @@ -66,18 +115,9 @@ func outboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, remotePu if err != nil { return nil, err } - if sessionToken != nil { - clogger.Debugf("session-token: %v", hexkey(sessionToken)) - } - - clogger.Debugf("initiator-nonce: %v", hexkey(initNonce)) - clogger.Debugf("initiator-random-private-key: %v", hexkey(crypto.FromECDSA(randomPrivKey))) - randomPublicKeyS, _ := exportPublicKey(&randomPrivKey.PublicKey) - clogger.Debugf("initiator-random-public-key: %v", hexkey(randomPublicKeyS)) if _, err = conn.Write(auth); err != nil { return nil, err } - clogger.Debugf("initiator handshake: %v", hexkey(auth)) response := make([]byte, rHSLen) if _, err = io.ReadFull(conn, response); err != nil { @@ -88,9 +128,6 @@ func outboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, remotePu return nil, err } - clogger.Debugf("receiver-nonce: %v", hexkey(recNonce)) - remoteRandomPubKeyS, _ := exportPublicKey(remoteRandomPubKey) - clogger.Debugf("receiver-random-public-key: %v", hexkey(remoteRandomPubKeyS)) return newSession(initNonce, recNonce, randomPrivKey, remoteRandomPubKey) } @@ -221,12 +258,9 @@ func inboundEncHandshake(conn io.ReadWriter, prvKey *ecdsa.PrivateKey, sessionTo if err != nil { return nil, nil, err } - clogger.Debugf("receiver-nonce: %v", hexkey(recNonce)) - clogger.Debugf("receiver-random-priv-key: %v", hexkey(crypto.FromECDSA(randomPrivKey))) if _, err = conn.Write(response); err != nil { return nil, nil, err } - clogger.Debugf("receiver handshake:\n%v", hexkey(response)) token, err = newSession(initNonce, recNonce, randomPrivKey, remoteRandomPubKey) return token, remotePubKey, err } @@ -361,3 +395,40 @@ func xor(one, other []byte) (xor []byte) { } return xor } + +func writeProtocolHandshake(w MsgWriter, our *protoHandshake) error { + return EncodeMsg(w, handshakeMsg, our.Version, our.Name, our.Caps, our.ListenPort, our.ID[:]) +} + +func readProtocolHandshake(r MsgReader, our *protoHandshake) (*protoHandshake, error) { + // read and handle remote handshake + msg, err := r.ReadMsg() + if err != nil { + return nil, err + } + if msg.Code == discMsg { + // disconnect before protocol handshake is valid according to the + // spec and we send it ourself if Server.addPeer fails. + var reason DiscReason + rlp.Decode(msg.Payload, &reason) + return nil, discRequestedError(reason) + } + if msg.Code != handshakeMsg { + return nil, fmt.Errorf("expected handshake, got %x", msg.Code) + } + if msg.Size > baseProtocolMaxMsgSize { + return nil, fmt.Errorf("message too big (%d > %d)", msg.Size, baseProtocolMaxMsgSize) + } + var hs protoHandshake + if err := msg.Decode(&hs); err != nil { + return nil, err + } + // validate handshake info + if hs.Version != our.Version { + return nil, newPeerError(errP2PVersionMismatch, "required version %d, received %d\n", baseProtocolVersion, hs.Version) + } + if (hs.ID == discover.NodeID{}) { + return nil, newPeerError(errPubkeyInvalid, "missing") + } + return &hs, nil +} diff --git a/p2p/crypto_test.go b/p2p/handshake_test.go similarity index 74% rename from p2p/crypto_test.go rename to p2p/handshake_test.go index 6cf0f4818d..06c6a69324 100644 --- a/p2p/crypto_test.go +++ b/p2p/handshake_test.go @@ -5,10 +5,12 @@ import ( "crypto/ecdsa" "crypto/rand" "net" + "reflect" "testing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/ethereum/go-ethereum/p2p/discover" ) func TestPublicKeyEncoding(t *testing.T) { @@ -91,14 +93,14 @@ func testCryptoHandshake(prv0, prv1 *ecdsa.PrivateKey, sessionToken []byte, t *t if err != nil { t.Errorf("%v", err) } - t.Logf("-> %v", hexkey(auth)) + // t.Logf("-> %v", hexkey(auth)) // receiver reads auth and responds with response response, remoteRecNonce, remoteInitNonce, _, remoteRandomPrivKey, remoteInitRandomPubKey, err := authResp(auth, sessionToken, prv1) if err != nil { t.Errorf("%v", err) } - t.Logf("<- %v\n", hexkey(response)) + // t.Logf("<- %v\n", hexkey(response)) // initiator reads receiver's response and the key exchange completes recNonce, remoteRandomPubKey, _, err := completeHandshake(response, prv0) @@ -132,7 +134,7 @@ func testCryptoHandshake(prv0, prv1 *ecdsa.PrivateKey, sessionToken []byte, t *t } } -func TestHandshake(t *testing.T) { +func TestEncHandshake(t *testing.T) { defer testlog(t).detach() prv0, _ := crypto.GenerateKey() @@ -165,3 +167,58 @@ func TestHandshake(t *testing.T) { t.Error("session token mismatch") } } + +func TestSetupConn(t *testing.T) { + prv0, _ := crypto.GenerateKey() + prv1, _ := crypto.GenerateKey() + node0 := &discover.Node{ + ID: discover.PubkeyID(&prv0.PublicKey), + IP: net.IP{1, 2, 3, 4}, + TCPPort: 33, + } + node1 := &discover.Node{ + ID: discover.PubkeyID(&prv1.PublicKey), + IP: net.IP{5, 6, 7, 8}, + TCPPort: 44, + } + hs0 := &protoHandshake{ + Version: baseProtocolVersion, + ID: node0.ID, + Caps: []Cap{{"a", 0}, {"b", 2}}, + } + hs1 := &protoHandshake{ + Version: baseProtocolVersion, + ID: node1.ID, + Caps: []Cap{{"c", 1}, {"d", 3}}, + } + fd0, fd1 := net.Pipe() + + done := make(chan struct{}) + go func() { + defer close(done) + conn0, err := setupConn(fd0, prv0, hs0, node1) + if err != nil { + t.Errorf("outbound side error: %v", err) + return + } + if conn0.ID != node1.ID { + t.Errorf("outbound conn id mismatch: got %v, want %v", conn0.ID, node1.ID) + } + if !reflect.DeepEqual(conn0.Caps, hs1.Caps) { + t.Errorf("outbound caps mismatch: got %v, want %v", conn0.Caps, hs1.Caps) + } + }() + + conn1, err := setupConn(fd1, prv1, hs1, nil) + if err != nil { + t.Fatalf("inbound side error: %v", err) + } + if conn1.ID != node0.ID { + t.Errorf("inbound conn id mismatch: got %v, want %v", conn1.ID, node0.ID) + } + if !reflect.DeepEqual(conn1.Caps, hs0.Caps) { + t.Errorf("inbound caps mismatch: got %v, want %v", conn1.Caps, hs0.Caps) + } + + <-done +} diff --git a/p2p/message.go b/p2p/message.go index 07916f7b3a..7adad4b09f 100644 --- a/p2p/message.go +++ b/p2p/message.go @@ -197,7 +197,7 @@ func (rw *frameRW) ReadMsg() (msg Msg, err error) { return msg, err } if !bytes.HasPrefix(start, magicToken) { - return msg, fmt.Errorf("bad magic token %x", start[:4], magicToken) + return msg, fmt.Errorf("bad magic token %x", start[:4]) } size := binary.BigEndian.Uint32(start[4:]) diff --git a/p2p/peer.go b/p2p/peer.go index fd5bec7d5d..b9bf0fd73b 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -33,37 +33,14 @@ const ( peersMsg = 0x05 ) -// handshake is the RLP structure of the protocol handshake. -type handshake struct { - Version uint64 - Name string - Caps []Cap - ListenPort uint64 - NodeID discover.NodeID -} - // Peer represents a connected remote node. type Peer struct { // Peers have all the log methods. // Use them to display messages related to the peer. *logger.Logger - infoMu sync.Mutex - name string - caps []Cap - - ourID, remoteID *discover.NodeID - ourName string - - rw *frameRW - - // These fields maintain the running protocols. - protocols []Protocol - runlock sync.RWMutex // protects running - running map[string]*proto - - // disables protocol handshake, for testing - noHandshake bool + rw *conn + running map[string]*protoRW protoWG sync.WaitGroup protoErr chan error @@ -73,36 +50,27 @@ type Peer struct { // NewPeer returns a peer for testing purposes. func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer { - conn, _ := net.Pipe() - peer := newPeer(conn, nil, "", nil, &id) - peer.setHandshakeInfo(name, caps) + pipe, _ := net.Pipe() + conn := newConn(pipe, &protoHandshake{ID: id, Name: name, Caps: caps}) + peer := newPeer(conn, nil) close(peer.closed) // ensures Disconnect doesn't block return peer } // ID returns the node's public key. func (p *Peer) ID() discover.NodeID { - return *p.remoteID + return p.rw.ID } // Name returns the node name that the remote node advertised. func (p *Peer) Name() string { - // this needs a lock because the information is part of the - // protocol handshake. - p.infoMu.Lock() - name := p.name - p.infoMu.Unlock() - return name + return p.rw.Name } // Caps returns the capabilities (supported subprotocols) of the remote peer. func (p *Peer) Caps() []Cap { - // this needs a lock because the information is part of the - // protocol handshake. - p.infoMu.Lock() - caps := p.caps - p.infoMu.Unlock() - return caps + // TODO: maybe return copy + return p.rw.Caps } // RemoteAddr returns the remote address of the network connection. @@ -126,30 +94,20 @@ func (p *Peer) Disconnect(reason DiscReason) { // String implements fmt.Stringer. func (p *Peer) String() string { - return fmt.Sprintf("Peer %.8x %v", p.remoteID[:], p.RemoteAddr()) + return fmt.Sprintf("Peer %.8x %v", p.rw.ID[:], p.RemoteAddr()) } -func newPeer(conn net.Conn, protocols []Protocol, ourName string, ourID, remoteID *discover.NodeID) *Peer { - logtag := fmt.Sprintf("Peer %.8x %v", remoteID[:], conn.RemoteAddr()) - return &Peer{ - Logger: logger.NewLogger(logtag), - rw: newFrameRW(conn, msgWriteTimeout), - ourID: ourID, - ourName: ourName, - remoteID: remoteID, - protocols: protocols, - running: make(map[string]*proto), - disc: make(chan DiscReason), - protoErr: make(chan error), - closed: make(chan struct{}), +func newPeer(conn *conn, protocols []Protocol) *Peer { + logtag := fmt.Sprintf("Peer %.8x %v", conn.ID[:], conn.RemoteAddr()) + p := &Peer{ + Logger: logger.NewLogger(logtag), + rw: conn, + running: matchProtocols(protocols, conn.Caps, conn), + disc: make(chan DiscReason), + protoErr: make(chan error), + closed: make(chan struct{}), } -} - -func (p *Peer) setHandshakeInfo(name string, caps []Cap) { - p.infoMu.Lock() - p.name = name - p.caps = caps - p.infoMu.Unlock() + return p } func (p *Peer) run() DiscReason { @@ -157,16 +115,9 @@ func (p *Peer) run() DiscReason { defer p.closeProtocols() defer close(p.closed) + p.startProtocols() go func() { readErr <- p.readLoop() }() - if !p.noHandshake { - if err := writeProtocolHandshake(p.rw, p.ourName, *p.ourID, p.protocols); err != nil { - p.DebugDetailf("Protocol handshake error: %v\n", err) - p.rw.Close() - return DiscProtocolError - } - } - // Wait for an error or disconnect. var reason DiscReason select { @@ -206,11 +157,6 @@ func (p *Peer) politeDisconnect(reason DiscReason) { } func (p *Peer) readLoop() error { - if !p.noHandshake { - if err := readProtocolHandshake(p, p.rw); err != nil { - return err - } - } for { msg, err := p.rw.ReadMsg() if err != nil { @@ -249,105 +195,51 @@ func (p *Peer) handle(msg Msg) error { return nil } -func readProtocolHandshake(p *Peer, rw MsgReadWriter) error { - // read and handle remote handshake - msg, err := rw.ReadMsg() - if err != nil { - return err - } - if msg.Code == discMsg { - // disconnect before protocol handshake is valid according to the - // spec and we send it ourself if Server.addPeer fails. - var reason DiscReason - rlp.Decode(msg.Payload, &reason) - return discRequestedError(reason) - } - if msg.Code != handshakeMsg { - return newPeerError(errProtocolBreach, "expected handshake, got %x", msg.Code) - } - if msg.Size > baseProtocolMaxMsgSize { - return newPeerError(errInvalidMsg, "message too big") - } - var hs handshake - if err := msg.Decode(&hs); err != nil { - return err - } - // validate handshake info - if hs.Version != baseProtocolVersion { - return newPeerError(errP2PVersionMismatch, "required version %d, received %d\n", - baseProtocolVersion, hs.Version) - } - if hs.NodeID == *p.remoteID { - return newPeerError(errPubkeyForbidden, "node ID mismatch") - } - // TODO: remove Caps with empty name - p.setHandshakeInfo(hs.Name, hs.Caps) - p.startSubprotocols(hs.Caps) - return nil -} - -func writeProtocolHandshake(w MsgWriter, name string, id discover.NodeID, ps []Protocol) error { - var caps []interface{} - for _, proto := range ps { - caps = append(caps, proto.cap()) - } - return EncodeMsg(w, handshakeMsg, baseProtocolVersion, name, caps, 0, id) -} - -// startProtocols starts matching named subprotocols. -func (p *Peer) startSubprotocols(caps []Cap) { +// matchProtocols creates structures for matching named subprotocols. +func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { sort.Sort(capsByName(caps)) - p.runlock.Lock() - defer p.runlock.Unlock() offset := baseProtocolLength + result := make(map[string]*protoRW) outer: for _, cap := range caps { - for _, proto := range p.protocols { - if proto.Name == cap.Name && - proto.Version == cap.Version && - p.running[cap.Name] == nil { - p.running[cap.Name] = p.startProto(offset, proto) + for _, proto := range protocols { + if proto.Name == cap.Name && proto.Version == cap.Version && result[cap.Name] == nil { + result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} offset += proto.Length continue outer } } } + return result } -func (p *Peer) startProto(offset uint64, impl Protocol) *proto { - p.DebugDetailf("Starting protocol %s/%d\n", impl.Name, impl.Version) - rw := &proto{ - name: impl.Name, - in: make(chan Msg), - offset: offset, - maxcode: impl.Length, - w: p.rw, +func (p *Peer) startProtocols() { + for _, proto := range p.running { + proto := proto + p.DebugDetailf("Starting protocol %s/%d\n", proto.Name, proto.Version) + p.protoWG.Add(1) + go func() { + err := proto.Run(p, proto) + if err == nil { + p.DebugDetailf("Protocol %s/%d returned\n", proto.Name, proto.Version) + err = errors.New("protocol returned") + } else { + p.DebugDetailf("Protocol %s/%d error: %v\n", proto.Name, proto.Version, err) + } + select { + case p.protoErr <- err: + case <-p.closed: + } + p.protoWG.Done() + }() } - p.protoWG.Add(1) - go func() { - err := impl.Run(p, rw) - if err == nil { - p.DebugDetailf("Protocol %s/%d returned\n", impl.Name, impl.Version) - err = errors.New("protocol returned") - } else { - p.DebugDetailf("Protocol %s/%d error: %v\n", impl.Name, impl.Version, err) - } - select { - case p.protoErr <- err: - case <-p.closed: - } - p.protoWG.Done() - }() - return rw } // getProto finds the protocol responsible for handling // the given message code. -func (p *Peer) getProto(code uint64) (*proto, error) { - p.runlock.RLock() - defer p.runlock.RUnlock() +func (p *Peer) getProto(code uint64) (*protoRW, error) { for _, proto := range p.running { - if code >= proto.offset && code < proto.offset+proto.maxcode { + if code >= proto.offset && code < proto.offset+proto.Length { return proto, nil } } @@ -355,46 +247,43 @@ func (p *Peer) getProto(code uint64) (*proto, error) { } func (p *Peer) closeProtocols() { - p.runlock.RLock() for _, p := range p.running { close(p.in) } - p.runlock.RUnlock() p.protoWG.Wait() } // writeProtoMsg sends the given message on behalf of the given named protocol. // this exists because of Server.Broadcast. func (p *Peer) writeProtoMsg(protoName string, msg Msg) error { - p.runlock.RLock() proto, ok := p.running[protoName] - p.runlock.RUnlock() if !ok { return fmt.Errorf("protocol %s not handled by peer", protoName) } - if msg.Code >= proto.maxcode { + if msg.Code >= proto.Length { return newPeerError(errInvalidMsgCode, "code %x is out of range for protocol %q", msg.Code, protoName) } msg.Code += proto.offset return p.rw.WriteMsg(msg) } -type proto struct { - name string - in chan Msg - maxcode, offset uint64 - w MsgWriter +type protoRW struct { + Protocol + + in chan Msg + offset uint64 + w MsgWriter } -func (rw *proto) WriteMsg(msg Msg) error { - if msg.Code >= rw.maxcode { +func (rw *protoRW) WriteMsg(msg Msg) error { + if msg.Code >= rw.Length { return newPeerError(errInvalidMsgCode, "not handled") } msg.Code += rw.offset return rw.w.WriteMsg(msg) } -func (rw *proto) ReadMsg() (Msg, error) { +func (rw *protoRW) ReadMsg() (Msg, error) { msg, ok := <-rw.in if !ok { return msg, io.EOF diff --git a/p2p/peer_test.go b/p2p/peer_test.go index 68c9910a26..a1260adbd7 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -6,11 +6,9 @@ import ( "io/ioutil" "net" "reflect" - "sort" "testing" "time" - "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/rlp" ) @@ -23,6 +21,7 @@ var discard = Protocol{ if err != nil { return err } + fmt.Printf("discarding %d\n", msg.Code) if err = msg.Discard(); err != nil { return err } @@ -30,13 +29,20 @@ var discard = Protocol{ }, } -func testPeer(noHandshake bool, protos []Protocol) (*frameRW, *Peer, <-chan DiscReason) { - conn1, conn2 := net.Pipe() - peer := newPeer(conn1, protos, "name", &discover.NodeID{}, &discover.NodeID{}) - peer.noHandshake = noHandshake +func testPeer(protos []Protocol) (*conn, *Peer, <-chan DiscReason) { + fd1, fd2 := net.Pipe() + hs1 := &protoHandshake{ID: randomID(), Version: baseProtocolVersion} + hs2 := &protoHandshake{ID: randomID(), Version: baseProtocolVersion} + for _, p := range protos { + hs1.Caps = append(hs1.Caps, p.cap()) + hs2.Caps = append(hs2.Caps, p.cap()) + } + + peer := newPeer(newConn(fd1, hs1), protos) errc := make(chan DiscReason, 1) go func() { errc <- peer.run() }() - return newFrameRW(conn2, msgWriteTimeout), peer, errc + + return newConn(fd2, hs2), peer, errc } func TestPeerProtoReadMsg(t *testing.T) { @@ -61,9 +67,8 @@ func TestPeerProtoReadMsg(t *testing.T) { }, } - rw, peer, errc := testPeer(true, []Protocol{proto}) + rw, _, errc := testPeer([]Protocol{proto}) defer rw.Close() - peer.startSubprotocols([]Cap{proto.cap()}) EncodeMsg(rw, baseProtocolLength+2, 1) EncodeMsg(rw, baseProtocolLength+3, 2) @@ -100,9 +105,8 @@ func TestPeerProtoReadLargeMsg(t *testing.T) { }, } - rw, peer, errc := testPeer(true, []Protocol{proto}) + rw, _, errc := testPeer([]Protocol{proto}) defer rw.Close() - peer.startSubprotocols([]Cap{proto.cap()}) EncodeMsg(rw, 18, make([]byte, msgsize)) select { @@ -130,9 +134,8 @@ func TestPeerProtoEncodeMsg(t *testing.T) { return nil }, } - rw, peer, _ := testPeer(true, []Protocol{proto}) + rw, _, _ := testPeer([]Protocol{proto}) defer rw.Close() - peer.startSubprotocols([]Cap{proto.cap()}) if err := expectMsg(rw, 17, []string{"foo", "bar"}); err != nil { t.Error(err) @@ -142,9 +145,8 @@ func TestPeerProtoEncodeMsg(t *testing.T) { func TestPeerWriteForBroadcast(t *testing.T) { defer testlog(t).detach() - rw, peer, peerErr := testPeer(true, []Protocol{discard}) + rw, peer, peerErr := testPeer([]Protocol{discard}) defer rw.Close() - peer.startSubprotocols([]Cap{discard.cap()}) // test write errors if err := peer.writeProtoMsg("b", NewMsg(3)); err == nil { @@ -160,7 +162,7 @@ func TestPeerWriteForBroadcast(t *testing.T) { read := make(chan struct{}) go func() { if err := expectMsg(rw, 16, nil); err != nil { - t.Error() + t.Error(err) } close(read) }() @@ -179,7 +181,7 @@ func TestPeerWriteForBroadcast(t *testing.T) { func TestPeerPing(t *testing.T) { defer testlog(t).detach() - rw, _, _ := testPeer(true, nil) + rw, _, _ := testPeer(nil) defer rw.Close() if err := EncodeMsg(rw, pingMsg); err != nil { t.Fatal(err) @@ -192,7 +194,7 @@ func TestPeerPing(t *testing.T) { func TestPeerDisconnect(t *testing.T) { defer testlog(t).detach() - rw, _, disc := testPeer(true, nil) + rw, _, disc := testPeer(nil) defer rw.Close() if err := EncodeMsg(rw, discMsg, DiscQuitting); err != nil { t.Fatal(err) @@ -206,73 +208,6 @@ func TestPeerDisconnect(t *testing.T) { } } -func TestPeerHandshake(t *testing.T) { - defer testlog(t).detach() - - // remote has two matching protocols: a and c - remote := NewPeer(randomID(), "", []Cap{{"a", 1}, {"b", 999}, {"c", 3}}) - remoteID := randomID() - remote.ourID = &remoteID - remote.ourName = "remote peer" - - start := make(chan string) - stop := make(chan struct{}) - run := func(p *Peer, rw MsgReadWriter) error { - name := rw.(*proto).name - if name != "a" && name != "c" { - t.Errorf("protocol %q should not be started", name) - } else { - start <- name - } - <-stop - return nil - } - protocols := []Protocol{ - {Name: "a", Version: 1, Length: 1, Run: run}, - {Name: "b", Version: 2, Length: 1, Run: run}, - {Name: "c", Version: 3, Length: 1, Run: run}, - {Name: "d", Version: 4, Length: 1, Run: run}, - } - rw, p, disc := testPeer(false, protocols) - p.remoteID = remote.ourID - defer rw.Close() - - // run the handshake - remoteProtocols := []Protocol{protocols[0], protocols[2]} - if err := writeProtocolHandshake(rw, "remote peer", remoteID, remoteProtocols); err != nil { - t.Fatalf("handshake write error: %v", err) - } - if err := readProtocolHandshake(remote, rw); err != nil { - t.Fatalf("handshake read error: %v", err) - } - - // check that all protocols have been started - var started []string - for i := 0; i < 2; i++ { - select { - case name := <-start: - started = append(started, name) - case <-time.After(100 * time.Millisecond): - } - } - sort.Strings(started) - if !reflect.DeepEqual(started, []string{"a", "c"}) { - t.Errorf("wrong protocols started: %v", started) - } - - // check that metadata has been set - if p.ID() != remoteID { - t.Errorf("peer has wrong node ID: got %v, want %v", p.ID(), remoteID) - } - if p.Name() != remote.ourName { - t.Errorf("peer has wrong node name: got %q, want %q", p.Name(), remote.ourName) - } - - close(stop) - expectMsg(rw, discMsg, nil) - t.Logf("disc reason: %v", <-disc) -} - func TestNewPeer(t *testing.T) { name := "nodename" caps := []Cap{{"foo", 2}, {"bar", 3}} diff --git a/p2p/server.go b/p2p/server.go index 35b584a273..194dc3f1c3 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -5,7 +5,6 @@ import ( "crypto/ecdsa" "errors" "fmt" - "io" "net" "runtime" "sync" @@ -83,9 +82,11 @@ type Server struct { // Hooks for testing. These are useful because we can inhibit // the whole protocol stack. - handshakeFunc + setupFunc newPeerHook + ourHandshake *protoHandshake + lock sync.RWMutex running bool listener net.Listener @@ -99,7 +100,7 @@ type Server struct { peerConnect chan *discover.Node } -type handshakeFunc func(io.ReadWriter, *ecdsa.PrivateKey, *discover.Node) (discover.NodeID, []byte, error) +type setupFunc func(net.Conn, *ecdsa.PrivateKey, *protoHandshake, *discover.Node) (*conn, error) type newPeerHook func(*Peer) // Peers returns all connected peers. @@ -170,8 +171,8 @@ func (srv *Server) Start() (err error) { srv.peers = make(map[discover.NodeID]*Peer) srv.peerConnect = make(chan *discover.Node) - if srv.handshakeFunc == nil { - srv.handshakeFunc = encHandshake + if srv.setupFunc == nil { + srv.setupFunc = setupConn } if srv.Blacklist == nil { srv.Blacklist = NewBlacklist() @@ -183,11 +184,17 @@ func (srv *Server) Start() (err error) { } // dial stuff - dt, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT) + ntab, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT) if err != nil { return err } - srv.ntab = dt + srv.ntab = ntab + + srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: ntab.Self()} + for _, p := range srv.Protocols { + srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap()) + } + if srv.Dialer == nil { srv.Dialer = &net.Dialer{Timeout: defaultDialTimeout} } @@ -347,18 +354,17 @@ func (srv *Server) findPeers() { } } -func (srv *Server) startPeer(conn net.Conn, dest *discover.Node) { +func (srv *Server) startPeer(fd net.Conn, dest *discover.Node) { // TODO: handle/store session token - conn.SetDeadline(time.Now().Add(handshakeTimeout)) - remoteID, _, err := srv.handshakeFunc(conn, srv.PrivateKey, dest) + fd.SetDeadline(time.Now().Add(handshakeTimeout)) + conn, err := srv.setupFunc(fd, srv.PrivateKey, srv.ourHandshake, dest) if err != nil { - conn.Close() - srvlog.Debugf("Encryption Handshake with %v failed: %v", conn.RemoteAddr(), err) + fd.Close() + srvlog.Debugf("Handshake with %v failed: %v", fd.RemoteAddr(), err) return } - ourID := srv.ntab.Self() - p := newPeer(conn, srv.Protocols, srv.Name, &ourID, &remoteID) - if ok, reason := srv.addPeer(remoteID, p); !ok { + p := newPeer(conn, srv.Protocols) + if ok, reason := srv.addPeer(conn.ID, p); !ok { srvlog.DebugDetailf("Not adding %v (%v)\n", p, reason) p.politeDisconnect(reason) return @@ -394,7 +400,7 @@ func (srv *Server) addPeer(id discover.NodeID, p *Peer) (bool, DiscReason) { func (srv *Server) removePeer(p *Peer) { srv.lock.Lock() - delete(srv.peers, *p.remoteID) + delete(srv.peers, p.ID()) srv.lock.Unlock() srv.peerWG.Done() } diff --git a/p2p/server_test.go b/p2p/server_test.go index aa2b3d2431..c109fffb93 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -21,8 +21,12 @@ func startTestServer(t *testing.T, pf newPeerHook) *Server { ListenAddr: "127.0.0.1:0", PrivateKey: newkey(), newPeerHook: pf, - handshakeFunc: func(io.ReadWriter, *ecdsa.PrivateKey, *discover.Node) (id discover.NodeID, st []byte, err error) { - return randomID(), nil, err + setupFunc: func(fd net.Conn, prv *ecdsa.PrivateKey, our *protoHandshake, dial *discover.Node) (*conn, error) { + id := randomID() + return &conn{ + frameRW: newFrameRW(fd, msgWriteTimeout), + protoHandshake: &protoHandshake{ID: id, Version: baseProtocolVersion}, + }, nil }, } if err := server.Start(); err != nil { @@ -116,9 +120,7 @@ func TestServerBroadcast(t *testing.T) { var connected sync.WaitGroup srv := startTestServer(t, func(p *Peer) { - p.protocols = []Protocol{discard} - p.startSubprotocols([]Cap{discard.cap()}) - p.noHandshake = true + p.running = matchProtocols([]Protocol{discard}, []Cap{discard.cap()}, p.rw) connected.Done() }) defer srv.Stop() From 1ec6190e866eeefd91ea82b31da9f94753685a4a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Feb 2015 16:39:20 +0100 Subject: [PATCH 17/78] cmd/mist: show peer names in peers window --- cmd/mist/assets/qml/main.qml | 3 ++- cmd/mist/gui.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index f9bfd9b8d2..31d240b5fc 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -927,7 +927,8 @@ ApplicationWindow { model: peerModel TableViewColumn{width: 180; role: "addr" ; title: "Remote Address" } TableViewColumn{width: 280; role: "nodeID" ; title: "Node ID" } - TableViewColumn{width: 180; role: "caps" ; title: "Capabilities" } + TableViewColumn{width: 100; role: "name" ; title: "Name" } + TableViewColumn{width: 40; role: "caps" ; title: "Capabilities" } } } } diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index c9419473ce..efab180641 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -466,7 +466,7 @@ NumGC: %d )) } -type qmlpeer struct{ Addr, NodeID, Caps string } +type qmlpeer struct{ Addr, NodeID, Name, Caps string } type peersByID []*qmlpeer @@ -481,6 +481,7 @@ func (gui *Gui) setPeerInfo() { qpeers[i] = &qmlpeer{ NodeID: p.ID().String(), Addr: p.RemoteAddr().String(), + Name: p.Name(), Caps: fmt.Sprint(p.Caps()), } } From 3dbd32093cd1060c339b3351fbb676b8c7cc31f0 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Feb 2015 16:53:52 +0100 Subject: [PATCH 18/78] p2p: enable devp2p ping This should prevent connection drops. --- p2p/peer.go | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/p2p/peer.go b/p2p/peer.go index b9bf0fd73b..fb027c834e 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -21,6 +21,7 @@ const ( baseProtocolMaxMsgSize = 10 * 1024 * 1024 disconnectGracePeriod = 2 * time.Second + pingInterval = 15 * time.Second ) const ( @@ -118,19 +119,33 @@ func (p *Peer) run() DiscReason { p.startProtocols() go func() { readErr <- p.readLoop() }() + ping := time.NewTicker(pingInterval) + defer ping.Stop() + // Wait for an error or disconnect. var reason DiscReason - select { - case err := <-readErr: - // We rely on protocols to abort if there is a write error. It - // might be more robust to handle them here as well. - p.DebugDetailf("Read error: %v\n", err) - p.rw.Close() - return DiscNetworkError - - case err := <-p.protoErr: - reason = discReasonForError(err) - case reason = <-p.disc: +loop: + for { + select { + case <-ping.C: + go func() { + if err := EncodeMsg(p.rw, pingMsg, nil); err != nil { + p.protoErr <- err + return + } + }() + case err := <-readErr: + // We rely on protocols to abort if there is a write error. It + // might be more robust to handle them here as well. + p.DebugDetailf("Read error: %v\n", err) + p.rw.Close() + return DiscNetworkError + case err := <-p.protoErr: + reason = discReasonForError(err) + break loop + case reason = <-p.disc: + break loop + } } p.politeDisconnect(reason) From dd871e791cdd2aefd001f6c3a11ac9378dde0bf5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Feb 2015 17:08:18 +0100 Subject: [PATCH 19/78] p2p: initialize Server.ourHandshake before accepting connections --- p2p/server.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index 194dc3f1c3..9237160112 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -160,7 +160,7 @@ func (srv *Server) Start() (err error) { } srvlog.Infoln("Starting Server") - // initialize all the fields + // static fields if srv.PrivateKey == nil { return fmt.Errorf("Server.PrivateKey must be set to a non-nil key") } @@ -170,31 +170,32 @@ func (srv *Server) Start() (err error) { srv.quit = make(chan struct{}) srv.peers = make(map[discover.NodeID]*Peer) srv.peerConnect = make(chan *discover.Node) - if srv.setupFunc == nil { srv.setupFunc = setupConn } if srv.Blacklist == nil { srv.Blacklist = NewBlacklist() } - if srv.ListenAddr != "" { - if err := srv.startListening(); err != nil { - return err - } - } - // dial stuff + // node table ntab, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT) if err != nil { return err } srv.ntab = ntab + // handshake srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: ntab.Self()} for _, p := range srv.Protocols { srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap()) } + // listen/dial + if srv.ListenAddr != "" { + if err := srv.startListening(); err != nil { + return err + } + } if srv.Dialer == nil { srv.Dialer = &net.Dialer{Timeout: defaultDialTimeout} } From fa15854a54d1d4505619aa3b3deabb50cd8ca881 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Feb 2015 17:09:13 +0100 Subject: [PATCH 20/78] logger: add P2P disconnected event --- logger/types.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/logger/types.go b/logger/types.go index d14a266433..7ab4a2b8c2 100644 --- a/logger/types.go +++ b/logger/types.go @@ -42,6 +42,16 @@ func (l *P2PConnected) EventName() string { return "p2p.connected" } +type P2PDisconnected struct { + NumConnections int `json:"num_connections"` + RemoteId string `json:"remote_id"` + LogEvent +} + +func (l *P2PDisconnected) EventName() string { + return "p2p.disconnected" +} + type EthMinerNewBlock struct { BlockHash string `json:"block_hash"` BlockNumber int `json:"block_number"` @@ -117,16 +127,6 @@ func (l *EthTxReceived) EventName() string { // return "p2p.handshaked" // } -// type P2PDisconnected struct { -// NumConnections int `json:"num_connections"` -// RemoteId string `json:"remote_id"` -// LogEvent -// } - -// func (l *P2PDisconnected) EventName() string { -// return "p2p.disconnected" -// } - // type P2PDisconnecting struct { // Reason string `json:"reason"` // RemoteId string `json:"remote_id"` From 3719db352a3de1c7daece71895abdd871616a2aa Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Feb 2015 17:09:33 +0100 Subject: [PATCH 21/78] p2p: emit JSON connect/disconnect events --- p2p/server.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/p2p/server.go b/p2p/server.go index 9237160112..3ea2538d1c 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -22,6 +22,7 @@ const ( ) var srvlog = logger.NewLogger("P2P Server") +var srvjslog = logger.NewJsonLogger() // MakeName creates a node name that follows the ethereum convention // for such names. It adds the operation system name and Go runtime version @@ -370,14 +371,26 @@ func (srv *Server) startPeer(fd net.Conn, dest *discover.Node) { p.politeDisconnect(reason) return } + srvlog.Debugf("Added %v\n", p) + srvjslog.LogJson(&logger.P2PConnected{ + RemoteId: fmt.Sprintf("%x", conn.ID[:]), + RemoteAddress: conn.RemoteAddr().String(), + RemoteVersionString: conn.Name, + NumConnections: srv.PeerCount(), + }) if srv.newPeerHook != nil { srv.newPeerHook(p) } discreason := p.run() srv.removePeer(p) + srvlog.Debugf("Removed %v (%v)\n", p, discreason) + srvjslog.LogJson(&logger.P2PDisconnected{ + RemoteId: fmt.Sprintf("%x", conn.ID[:]), + NumConnections: srv.PeerCount(), + }) } func (srv *Server) addPeer(id discover.NodeID, p *Peer) (bool, DiscReason) { From 605dd3a9820bb74be883afe3cb0e462aca40b32d Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 19 Feb 2015 18:41:50 +0100 Subject: [PATCH 22/78] Add serpent compilation to RPC --- rpc/message.go | 15 +++++++++++++++ rpc/packages.go | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/rpc/message.go b/rpc/message.go index 524d7fc848..1935bf1e25 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -201,6 +201,21 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { return args, nil } +func (req *RpcRequest) ToCompileArgs() (string, error) { + if len(req.Params) < 1 { + return "", NewErrorResponse(ErrorArguments) + } + + var args string + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return "", NewErrorResponse(ErrorDecodeArgs) + } + + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToFilterArgs() (*FilterOptions, error) { if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) diff --git a/rpc/packages.go b/rpc/packages.go index 216321dba5..c969f58ccb 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -300,6 +300,21 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { return nil } +func (p *EthereumApi) GetCompilers(reply *interface{}) error { + c := []string{"serpent"} + *reply = c + return nil +} + +func (p *EthereumApi) CompileSerpent(script string, reply *interface{}) error { + res, err := ethutil.Compile(script, false) + if err != nil { + return err + } + *reply = res + return nil +} + func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error { *reply = toHex(crypto.Sha3(fromHex(args.Data))) return nil @@ -490,6 +505,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.WatchTx(args, reply) + case "eth_compilers": + return p.GetCompilers(reply) + case "eth_serpent": + args, err := req.ToCompileArgs() + if err != nil { + return err + } + return p.CompileSerpent(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { From a59cd94625f589bb167be7a9c4588ff959dcfc00 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 19 Feb 2015 18:58:15 +0100 Subject: [PATCH 23/78] Add setMining RPC method --- rpc/message.go | 15 +++++++++++++++ rpc/packages.go | 11 +++++++++++ xeth/xeth.go | 11 +++++++++++ 3 files changed, 37 insertions(+) diff --git a/rpc/message.go b/rpc/message.go index 1935bf1e25..d02acef0e1 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -201,6 +201,21 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { return args, nil } +func (req *RpcRequest) ToBoolArgs() (bool, error) { + if len(req.Params) < 1 { + return false, NewErrorResponse(ErrorArguments) + } + + var args bool + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return false, NewErrorResponse(ErrorDecodeArgs) + } + + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToCompileArgs() (string, error) { if len(req.Params) < 1 { return "", NewErrorResponse(ErrorArguments) diff --git a/rpc/packages.go b/rpc/packages.go index c969f58ccb..d82538c929 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -267,6 +267,11 @@ func (p *EthereumApi) GetIsMining(reply *interface{}) error { return nil } +func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error { + *reply = p.xeth.SetMining(shouldmine) + return nil +} + func (p *EthereumApi) BlockNumber(reply *interface{}) error { *reply = p.xeth.Backend().ChainManager().CurrentBlock().Number() return nil @@ -400,6 +405,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return p.GetIsListening(reply) case "eth_mining": return p.GetIsMining(reply) + case "eth_setMining": + args, err := req.ToBoolArgs() + if err != nil { + return err + } + return p.SetMining(args, reply) case "eth_peerCount": return p.GetPeerCount(reply) case "eth_number": diff --git a/xeth/xeth.go b/xeth/xeth.go index f005105bb2..06915c5e03 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -102,6 +102,17 @@ func (self *XEth) IsMining() bool { return self.miner.Mining() } +func (self *XEth) SetMining(shouldmine bool) bool { + ismining := self.miner.Mining() + if shouldmine && !ismining { + self.miner.Start() + } + if ismining && !shouldmine { + self.miner.Stop() + } + return self.miner.Mining() +} + func (self *XEth) IsListening() bool { return self.eth.IsListening() } From fa4cbad315609e41d88c59ecbce7c6c6169fc57a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 22:33:22 +0100 Subject: [PATCH 24/78] Optimisations and fixed a couple of DDOS issues in the miner --- cmd/mist/assets/examples/bomb.html | 22 +++++++++++++++ cmd/mist/gui.go | 20 ++----------- core/block_processor.go | 25 +++++++++-------- core/chain_manager.go | 25 +++++++++++++---- core/error.go | 17 ----------- core/events.go | 3 ++ core/state_transition.go | 3 +- core/transaction_pool.go | 33 ++++++++++++++++------ ethutil/common.go | 7 +++++ miner/worker.go | 22 +++++++++------ pow/ezp/pow.go | 2 +- rpc/packages.go | 1 + state/state_object.go | 4 +++ state/statedb.go | 45 +++++++++++++++++------------- xeth/xeth.go | 29 ++++++++++--------- 15 files changed, 155 insertions(+), 103 deletions(-) create mode 100644 cmd/mist/assets/examples/bomb.html diff --git a/cmd/mist/assets/examples/bomb.html b/cmd/mist/assets/examples/bomb.html new file mode 100644 index 0000000000..62540f9bb6 --- /dev/null +++ b/cmd/mist/assets/examples/bomb.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index 1e3efd269f..afddeb8f6c 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -387,14 +387,11 @@ func (gui *Gui) update() { generalUpdateTicker := time.NewTicker(500 * time.Millisecond) statsUpdateTicker := time.NewTicker(5 * time.Second) - state := gui.eth.ChainManager().TransState() - - gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Balance()))) - lastBlockLabel := gui.getObjectByName("lastBlockLabel") miningLabel := gui.getObjectByName("miningLabel") events := gui.eth.EventMux().Subscribe( + core.ChainEvent{}, core.TxPreEvent{}, core.TxPostEvent{}, ) @@ -407,6 +404,8 @@ func (gui *Gui) update() { return } switch ev := ev.(type) { + case core.ChainEvent: + gui.processBlock(ev.Block, false) case core.TxPreEvent: gui.insertTransaction("pre", ev.Tx) @@ -422,19 +421,6 @@ func (gui *Gui) update() { lastBlockLabel.Set("text", statusText) miningLabel.Set("text", "Mining @ "+strconv.FormatInt(gui.uiLib.Miner().HashRate(), 10)+"/Khash") - /* - blockLength := gui.eth.BlockPool().BlocksProcessed - chainLength := gui.eth.BlockPool().ChainLength - - var ( - pct float64 = 1.0 / float64(chainLength) * float64(blockLength) - dlWidget = gui.win.Root().ObjectByName("downloadIndicator") - dlLabel = gui.win.Root().ObjectByName("downloadLabel") - ) - dlWidget.Set("value", pct) - dlLabel.Set("text", fmt.Sprintf("%d / %d", blockLength, chainLength)) - */ - case <-statsUpdateTicker.C: gui.setStatsPane() } diff --git a/core/block_processor.go b/core/block_processor.go index b4449100f3..a9795385fb 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -73,24 +73,27 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block return receipts, nil } -func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, state *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) { +func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) { // If we are mining this block and validating we want to set the logs back to 0 - state.EmptyLogs() + statedb.EmptyLogs() txGas := new(big.Int).Set(tx.Gas()) - cb := state.GetStateObject(coinbase.Address()) - st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb) + cb := statedb.GetStateObject(coinbase.Address()) + st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb) _, err := st.TransitionState() + if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err)) { + return nil, nil, err + } txGas.Sub(txGas, st.gas) // Update the state with pending changes - state.Update(txGas) + statedb.Update(txGas) cumulative := new(big.Int).Set(usedGas.Add(usedGas, txGas)) - receipt := types.NewReceipt(state.Root(), cumulative) - receipt.SetLogs(state.Logs()) + receipt := types.NewReceipt(statedb.Root(), cumulative) + receipt.SetLogs(statedb.Logs()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) chainlogger.Debugln(receipt) @@ -99,12 +102,12 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, state go self.eventMux.Post(TxPostEvent{tx}) } - go self.eventMux.Post(state.Logs()) + go self.eventMux.Post(statedb.Logs()) return receipt, txGas, err } -func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) { +func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) { var ( receipts types.Receipts handled, unhandled types.Transactions @@ -115,12 +118,12 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state ) for _, tx := range txs { - receipt, txGas, err := self.ApplyTransaction(coinbase, state, block, tx, totalUsedGas, transientProcess) + receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess) if err != nil { switch { case IsNonceErr(err): return nil, nil, nil, nil, err - case IsGasLimitErr(err): + case state.IsGasLimitErr(err): return nil, nil, nil, nil, err default: statelogger.Infoln(err) diff --git a/core/chain_manager.go b/core/chain_manager.go index 2862820644..003781791c 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -134,14 +134,11 @@ func (self *ChainManager) State() *state.StateDB { func (self *ChainManager) TransState() *state.StateDB { self.tsmu.RLock() defer self.tsmu.RUnlock() - //tmp := self.transState return self.transState } func (self *ChainManager) setTransState(statedb *state.StateDB) { - self.tsmu.Lock() - defer self.tsmu.Unlock() self.transState = statedb } @@ -361,6 +358,9 @@ func (bc *ChainManager) Stop() { } func (self *ChainManager) InsertChain(chain types.Blocks) error { + self.tsmu.Lock() + defer self.tsmu.Unlock() + for _, block := range chain { td, err := self.processor.Process(block) if err != nil { @@ -376,6 +376,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } block.Td = td + var chain, split bool self.mu.Lock() { self.write(block) @@ -383,16 +384,26 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { 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) + split = true } self.setTotalDifficulty(td) self.insert(block) - self.setTransState(state.New(cblock.Root(), self.db)) - self.eventMux.Post(ChainEvent{block, td}) + chain = true } } self.mu.Unlock() + + if chain { + //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.eventMux.Post(ChainSplitEvent{block}) + } } return nil @@ -402,3 +413,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { func (self *ChainManager) GetAccount(addr []byte) *state.StateObject { return self.State().GetAccount(addr) } + +func (self *ChainManager) TransMut() *sync.RWMutex { + return &self.tsmu +} diff --git a/core/error.go b/core/error.go index 6af48ac2de..e86bacb2d3 100644 --- a/core/error.go +++ b/core/error.go @@ -68,23 +68,6 @@ func IsValidationErr(err error) bool { return ok } -type GasLimitErr struct { - Message string - Is, Max *big.Int -} - -func IsGasLimitErr(err error) bool { - _, ok := err.(*GasLimitErr) - - return ok -} -func (err *GasLimitErr) Error() string { - return err.Message -} -func GasLimitError(is, max *big.Int) *GasLimitErr { - return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max} -} - type NonceErr struct { Message string Is, Exp uint64 diff --git a/core/events.go b/core/events.go index fe106da496..4cbbc609ca 100644 --- a/core/events.go +++ b/core/events.go @@ -13,3 +13,6 @@ type NewBlockEvent struct{ Block *types.Block } // NewMinedBlockEvent is posted when a block has been imported. type NewMinedBlockEvent struct{ Block *types.Block } + +// ChainSplit is posted when a new head is detected +type ChainSplitEvent struct{ Block *types.Block } diff --git a/core/state_transition.go b/core/state_transition.go index 33dd45f023..e82be647db 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -166,7 +166,8 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { defer self.RefundGas() // Increment the nonce for the next transaction - sender.Nonce += 1 + self.state.SetNonce(sender.Address(), sender.Nonce+1) + //sender.Nonce += 1 // Transaction gas if err = self.UseGas(vm.GasTx); err != nil { diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 7a901fcae5..894b6c440c 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -3,6 +3,7 @@ package core import ( "errors" "fmt" + "sync" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethutil" @@ -35,6 +36,7 @@ type TxProcessor interface { // guarantee a non blocking pool we use a queue channel which can be // independently read without needing access to the actual pool. type TxPool struct { + mu sync.RWMutex // Queueing channel for reading and writing incoming // transactions to queueChan chan *types.Transaction @@ -97,7 +99,7 @@ func (self *TxPool) addTx(tx *types.Transaction) { self.txs[string(tx.Hash())] = tx } -func (self *TxPool) Add(tx *types.Transaction) error { +func (self *TxPool) add(tx *types.Transaction) error { if self.txs[string(tx.Hash())] != nil { return fmt.Errorf("Known transaction (%x)", tx.Hash()[0:4]) } @@ -128,17 +130,28 @@ func (self *TxPool) Size() int { return len(self.txs) } +func (self *TxPool) Add(tx *types.Transaction) error { + self.mu.Lock() + defer self.mu.Unlock() + return self.add(tx) +} func (self *TxPool) AddTransactions(txs []*types.Transaction) { + self.mu.Lock() + defer self.mu.Unlock() + for _, tx := range txs { - if err := self.Add(tx); err != nil { - txplogger.Infoln(err) + if err := self.add(tx); err != nil { + txplogger.Debugln(err) } else { - txplogger.Infof("tx %x\n", tx.Hash()[0:4]) + txplogger.Debugf("tx %x\n", tx.Hash()[0:4]) } } } func (self *TxPool) GetTransactions() (txs types.Transactions) { + self.mu.RLock() + defer self.mu.RUnlock() + txs = make(types.Transactions, self.Size()) i := 0 for _, tx := range self.txs { @@ -150,30 +163,32 @@ func (self *TxPool) GetTransactions() (txs types.Transactions) { } func (pool *TxPool) RemoveInvalid(query StateQuery) { + pool.mu.Lock() + var removedTxs types.Transactions for _, tx := range pool.txs { sender := query.GetAccount(tx.From()) err := pool.ValidateTransaction(tx) - fmt.Println(err, sender.Nonce, tx.Nonce()) if err != nil || sender.Nonce >= tx.Nonce() { removedTxs = append(removedTxs, tx) } } + pool.mu.Unlock() pool.RemoveSet(removedTxs) } func (self *TxPool) RemoveSet(txs types.Transactions) { + self.mu.Lock() + defer self.mu.Unlock() + for _, tx := range txs { delete(self.txs, string(tx.Hash())) } } -func (pool *TxPool) Flush() []*types.Transaction { - txList := pool.GetTransactions() +func (pool *TxPool) Flush() { pool.txs = make(map[string]*types.Transaction) - - return txList } func (pool *TxPool) Start() { diff --git a/ethutil/common.go b/ethutil/common.go index 271c56fd54..2ef2440c78 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" "runtime" + "time" ) func IsWindows() bool { @@ -86,3 +87,9 @@ var ( Big256 = big.NewInt(0xff) Big257 = big.NewInt(257) ) + +func Bench(pre string, cb func()) { + start := time.Now() + cb() + fmt.Println(pre, ": took:", time.Since(start)) +} diff --git a/miner/worker.go b/miner/worker.go index 47b462e537..1f3a52ab52 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -109,14 +109,18 @@ func (self *worker) register(agent Agent) { } func (self *worker) update() { - events := self.mux.Subscribe(core.ChainEvent{}, core.TxPreEvent{}) + events := self.mux.Subscribe(core.ChainEvent{}, core.NewMinedBlockEvent{}) out: for { select { case event := <-events.Chan(): - switch event.(type) { - case core.ChainEvent, core.TxPreEvent: + switch ev := event.(type) { + case core.ChainEvent: + if self.current.block != ev.Block { + self.commitNewWork() + } + case core.NewMinedBlockEvent: self.commitNewWork() } case <-self.quit: @@ -172,17 +176,19 @@ func (self *worker) commitNewWork() { transactions := self.eth.TxPool().GetTransactions() sort.Sort(types.TxByNonce{transactions}) + minerlogger.Infof("committing new work with %d txs\n", len(transactions)) // Keep track of transactions which return errors so they can be removed var remove types.Transactions +gasLimit: for _, tx := range transactions { err := self.commitTransaction(tx) switch { case core.IsNonceErr(err): // Remove invalid transactions remove = append(remove, tx) - case core.IsGasLimitErr(err): + case state.IsGasLimitErr(err): // Break on gas limit - break + break gasLimit } if err != nil { @@ -227,11 +233,9 @@ func (self *worker) commitUncle(uncle *types.Header) error { } func (self *worker) commitTransaction(tx *types.Transaction) error { - snapshot := self.current.state.Copy() + //fmt.Printf("proc %x %v\n", tx.Hash()[:3], tx.Nonce()) receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true) - if err != nil && (core.IsNonceErr(err) || core.IsGasLimitErr(err)) { - self.current.state.Set(snapshot) - + if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err)) { return err } diff --git a/pow/ezp/pow.go b/pow/ezp/pow.go index 540381243f..f4a8b80e5e 100644 --- a/pow/ezp/pow.go +++ b/pow/ezp/pow.go @@ -21,7 +21,7 @@ type EasyPow struct { } func New() *EasyPow { - return &EasyPow{turbo: false} + return &EasyPow{turbo: true} } func (pow *EasyPow) GetHashrate() int64 { diff --git a/rpc/packages.go b/rpc/packages.go index 7044d9d127..63eea54d6d 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -180,6 +180,7 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { result, _ := p.xeth.Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) *reply = result } + return nil } diff --git a/state/state_object.go b/state/state_object.go index eaa91c7133..d50c9fd7a9 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -53,6 +53,7 @@ type StateObject struct { // When an object is marked for deletion it will be delete from the trie // during the "update" phase of the state transition remove bool + dirty bool } func (self *StateObject) Reset() { @@ -211,6 +212,8 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { return GasLimitError(self.gasPool, gas) } + self.gasPool.Sub(self.gasPool, gas) + rGas := new(big.Int).Set(gas) rGas.Mul(rGas, price) @@ -241,6 +244,7 @@ func (self *StateObject) Copy() *StateObject { stateObject.storage = self.storage.Copy() stateObject.gasPool.Set(self.gasPool) stateObject.remove = self.remove + stateObject.dirty = self.dirty return stateObject } diff --git a/state/statedb.go b/state/statedb.go index c83d59ed77..8c8a21db99 100644 --- a/state/statedb.go +++ b/state/statedb.go @@ -78,43 +78,45 @@ func (self *StateDB) GetNonce(addr []byte) uint64 { return 0 } -func (self *StateDB) SetNonce(addr []byte, nonce uint64) { +func (self *StateDB) GetCode(addr []byte) []byte { stateObject := self.GetStateObject(addr) if stateObject != nil { - stateObject.Nonce = nonce + return stateObject.Code } + + return nil } -func (self *StateDB) GetCode(addr []byte) []byte { - stateObject := self.GetStateObject(addr) +func (self *StateDB) GetState(a, b []byte) []byte { + stateObject := self.GetStateObject(a) if stateObject != nil { - return stateObject.Code + return stateObject.GetState(b).Bytes() } return nil } -func (self *StateDB) SetCode(addr, code []byte) { +func (self *StateDB) SetNonce(addr []byte, nonce uint64) { stateObject := self.GetStateObject(addr) if stateObject != nil { - stateObject.SetCode(code) + stateObject.Nonce = nonce + stateObject.dirty = true } } -// TODO vars -func (self *StateDB) GetState(a, b []byte) []byte { - stateObject := self.GetStateObject(a) +func (self *StateDB) SetCode(addr, code []byte) { + stateObject := self.GetStateObject(addr) if stateObject != nil { - return stateObject.GetState(b).Bytes() + stateObject.SetCode(code) + stateObject.dirty = true } - - return nil } func (self *StateDB) SetState(addr, key []byte, value interface{}) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetState(key, ethutil.NewValue(value)) + stateObject.dirty = true } } @@ -122,6 +124,7 @@ func (self *StateDB) Delete(addr []byte) bool { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.MarkForDeletion() + stateObject.dirty = true return true } @@ -282,16 +285,18 @@ func (self *StateDB) Refunds() map[string]*big.Int { } func (self *StateDB) Update(gasUsed *big.Int) { - self.refund = make(map[string]*big.Int) for _, stateObject := range self.stateObjects { - if stateObject.remove { - self.DeleteStateObject(stateObject) - } else { - stateObject.Sync() - - self.UpdateStateObject(stateObject) + if stateObject.dirty { + if stateObject.remove { + self.DeleteStateObject(stateObject) + } else { + stateObject.Sync() + + self.UpdateStateObject(stateObject) + } + stateObject.dirty = false } } } diff --git a/xeth/xeth.go b/xeth/xeth.go index f005105bb2..d578c03c9f 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -7,6 +7,7 @@ package xeth import ( "bytes" "encoding/json" + "fmt" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -241,7 +242,6 @@ func (self *XEth) Call(toStr, valueStr, gasStr, gasPriceStr, dataStr string) (st } func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { - var ( to []byte value = ethutil.NewValue(valueStr) @@ -265,29 +265,32 @@ func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string) tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data) } - state := self.chainManager.TransState() + var err error + state := self.eth.ChainManager().TransState() + if balance := state.GetBalance(key.Address()); balance.Cmp(tx.Value()) < 0 { + return "", fmt.Errorf("insufficient balance. balance=%v tx=%v", balance, tx.Value()) + } nonce := state.GetNonce(key.Address()) tx.SetNonce(nonce) tx.Sign(key.PrivateKey) - // 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) + //fmt.Printf("create tx: %x %v\n", tx.Hash()[:4], tx.Nonce()) - err := self.eth.TxPool().Add(tx) + /* + // Do some pre processing for our "pre" events and hooks + block := self.chainManager.NewBlock(key.Address()) + coinbase := state.GetOrNewStateObject(key.Address()) + coinbase.SetGasPool(block.GasLimit()) + self.blockProcessor.ApplyTransactions(coinbase, state, block, types.Transactions{tx}, true) + */ + + err = self.eth.TxPool().Add(tx) if err != nil { return "", err } state.SetNonce(key.Address(), nonce+1) - if contractCreation { - addr := core.AddressFromMessage(tx) - pipelogger.Infof("Contract addr %x\n", addr) - } - if types.IsContractAddr(to) { return toHex(core.AddressFromMessage(tx)), nil } From 81dea2d8e796b60ca9325bd2a3e502b71e25e6cc Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 11:35:40 +0100 Subject: [PATCH 25/78] update-license.go: add blank line after build tag This silences "go install ./...". For some reason it started complaining with go 1.4.2. --- update-license.go | 1 + 1 file changed, 1 insertion(+) diff --git a/update-license.go b/update-license.go index d5e21fdd3f..832a94712f 100644 --- a/update-license.go +++ b/update-license.go @@ -1,4 +1,5 @@ // +build none + /* This command generates GPL license headers on top of all source files. You can run it once per month, before cutting a release or just From 4ab7a290cdc6495a7ebcea9384cdc6622f2fd000 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 11:36:50 +0100 Subject: [PATCH 26/78] accounts: use crypto/randentropy in test --- accounts/accounts_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go index da9406ebe8..30e8c62855 100644 --- a/accounts/accounts_test.go +++ b/accounts/accounts_test.go @@ -1,8 +1,10 @@ package accounts import ( - "github.com/ethereum/go-ethereum/crypto" "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/randentropy" ) func TestAccountManager(t *testing.T) { @@ -10,7 +12,7 @@ func TestAccountManager(t *testing.T) { am := NewAccountManager(ks) pass := "" // not used but required by API a1, err := am.NewAccount(pass) - toSign := crypto.GetEntropyCSPRNG(32) + toSign := randentropy.GetEntropyCSPRNG(32) _, err = am.Sign(a1, pass, toSign) if err != nil { t.Fatal(err) From 01ce066d4307e6e8cab815eab9295a0b259130b9 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 11:37:33 +0100 Subject: [PATCH 27/78] state: improve TestDump --- state/state_test.go | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/state/state_test.go b/state/state_test.go index 7c54cedc0e..ee1cf92866 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -1,6 +1,8 @@ package state import ( + "math/big" + checker "gopkg.in/check.v1" "github.com/ethereum/go-ethereum/ethdb" @@ -16,11 +18,42 @@ var _ = checker.Suite(&StateSuite{}) // var ZeroHash256 = make([]byte, 32) func (s *StateSuite) TestDump(c *checker.C) { - key := []byte{0x01} - value := []byte("foo") - s.state.trie.Update(key, value) - dump := s.state.Dump() - c.Assert(dump, checker.NotNil) + // generate a few entries + obj1 := s.state.GetOrNewStateObject([]byte{0x01}) + obj1.AddBalance(big.NewInt(22)) + obj2 := s.state.GetOrNewStateObject([]byte{0x01, 0x02}) + obj2.SetCode([]byte{3, 3, 3, 3, 3, 3, 3}) + obj3 := s.state.GetOrNewStateObject([]byte{0x02}) + obj3.SetBalance(big.NewInt(44)) + + // write some of them to the trie + s.state.UpdateStateObject(obj1) + s.state.UpdateStateObject(obj2) + + // check that dump contains the state objects that are in trie + got := string(s.state.Dump()) + want := `{ + "root": "4e3a59299745ba6752247c8b91d0f716dac9ec235861c91f5ac1894a361d87ba", + "accounts": { + "0000000000000000000000000000000000000001": { + "balance": "22", + "nonce": 0, + "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "storage": {} + }, + "0000000000000000000000000000000000000102": { + "balance": "0", + "nonce": 0, + "root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "codeHash": "87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3", + "storage": {} + } + } +}` + if got != want { + c.Errorf("dump mismatch:\ngot: %s\nwant: %s\n", got, want) + } } func (s *StateSuite) SetUpTest(c *checker.C) { From b3b6210886abd0962f97add91c081ac732639102 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 11:38:52 +0100 Subject: [PATCH 28/78] tests/vm: add non-test Go file This removes the annoying warning printed by "go install ./...". --- tests/vm/nowarn.go | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/vm/nowarn.go diff --git a/tests/vm/nowarn.go b/tests/vm/nowarn.go new file mode 100644 index 0000000000..2a45a6cc64 --- /dev/null +++ b/tests/vm/nowarn.go @@ -0,0 +1,3 @@ +// This silences the warning given by 'go install ./...'. + +package vm From 66abe2e3d43c1004630c0c2f52a7f427bd51293b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 11:55:13 +0100 Subject: [PATCH 29/78] gocoverage.sh: skip . This is an attempt to get Travis working again. --- gocoverage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gocoverage.sh b/gocoverage.sh index 4245e3901c..d353bd08a3 100755 --- a/gocoverage.sh +++ b/gocoverage.sh @@ -13,7 +13,7 @@ for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d) do if ls $dir/*.go &> /dev/null; then # echo $dir - if [[ $dir != "./tests/vm" ]] + if [[ $dir != "./tests/vm" && $dir != "." ]] then go test -covermode=count -coverprofile=$dir/profile.tmp $dir fi From 654f7f707c9bd327fcbf0dcb89715a5930f915eb Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 12:15:08 +0100 Subject: [PATCH 30/78] .travis.yml: speed up tests on Travis This should decrease test runtime to about 30 seconds. --- .travis.yml | 3 --- gocoverage.sh | 11 ++++++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2dfb7e283d..cf8b02f5cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,7 @@ install: # - 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 - - go get gopkg.in/check.v1 - - go get github.com/tools/godep before_script: - - godep restore - gofmt -l -w . - goimports -l -w . - golint . diff --git a/gocoverage.sh b/gocoverage.sh index d353bd08a3..e54a5cab03 100755 --- a/gocoverage.sh +++ b/gocoverage.sh @@ -1,11 +1,16 @@ #!/bin/bash -# The script does automatic checking on a Go package and its sub-packages, including: -# 6. test coverage (http://blog.golang.org/cover) set -e -# Run test coverage on each subdirectories and merge the coverage profile. +# Add godep workspace to GOPATH. We do it manually instead of using +# 'godep go test' or 'godep restore' so godep doesn't need to be installed. +GOPATH="$PWD/Godeps/_workspace:$GOPATH" + +# Install packages before testing. Not doing this would cause +# 'go test' to recompile all package dependencies before testing each package. +go install ./... +# Run test coverage on each subdirectories and merge the coverage profile. echo "mode: count" > profile.cov # Standard go tooling behavior is to ignore dirs with leading underscors From 3b12a9293c35fd336122d9387ab6bc9b67d2803a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 12:17:24 +0100 Subject: [PATCH 31/78] .travis.yml: don't run gofmt, goimports, golint This should yield another 30-second speed up. Nobody looks at the output of those anyway. We might want bring back gofmt later and actually fail the build if source is not formatted. --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index cf8b02f5cd..1b31048267 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,15 +6,10 @@ before_install: - 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: From 982f73fa6d6f12874729faacd0db14fc78d518dd Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 12:59:54 +0100 Subject: [PATCH 32/78] Added timeout for filter & removed clipboard. Closes #350 --- rpc/packages.go | 72 ++++++++++++++++++++++++++++------- rpc/packages_test.go | 37 ++++++++++++++++++ rpc/util.go | 33 ++++++++++++++++ ui/qt/clipboard/capi.hpp | 11 ------ ui/qt/clipboard/clipboard.cpp | 20 ---------- ui/qt/clipboard/clipboard.go | 15 -------- ui/qt/clipboard/clipboard.hpp | 23 ----------- 7 files changed, 129 insertions(+), 82 deletions(-) create mode 100644 rpc/packages_test.go delete mode 100644 ui/qt/clipboard/capi.hpp delete mode 100644 ui/qt/clipboard/clipboard.cpp delete mode 100644 ui/qt/clipboard/clipboard.go delete mode 100644 ui/qt/clipboard/clipboard.hpp diff --git a/rpc/packages.go b/rpc/packages.go index 63eea54d6d..7411392c2f 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -13,6 +13,7 @@ import ( "math/big" "strings" "sync" + "time" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -31,13 +32,14 @@ const ( type EthereumApi struct { xeth *xeth.XEth + quit chan struct{} filterManager *filter.FilterManager logMut sync.RWMutex - logs map[int]state.Logs + logs map[int]*logFilter messagesMut sync.RWMutex - messages map[int][]xeth.WhisperMessage + messages map[int]*whisperFilter // Register keeps a list of accounts and transaction data regmut sync.Mutex register map[string][]*NewTxArgs @@ -49,12 +51,14 @@ func NewEthereumApi(eth *xeth.XEth) *EthereumApi { db, _ := ethdb.NewLDBDatabase("dapps") api := &EthereumApi{ xeth: eth, + quit: make(chan struct{}), filterManager: filter.NewFilterManager(eth.Backend().EventMux()), - logs: make(map[int]state.Logs), - messages: make(map[int][]xeth.WhisperMessage), + logs: make(map[int]*logFilter), + messages: make(map[int]*whisperFilter), db: db, } go api.filterManager.Start() + go api.start() return api } @@ -97,7 +101,11 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro self.logMut.Lock() defer self.logMut.Unlock() - self.logs[id] = append(self.logs[id], logs...) + if self.logs[id] == nil { + self.logs[id] = &logFilter{timeout: time.Now()} + } + + self.logs[id].add(logs...) } id = self.filterManager.InstallFilter(filter) *reply = id @@ -113,7 +121,11 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error self.logMut.Lock() defer self.logMut.Unlock() - self.logs[id] = append(self.logs[id], &state.StateLog{}) + if self.logs[id] == nil { + self.logs[id] = &logFilter{timeout: time.Now()} + } + + self.logs[id].add(&state.StateLog{}) } if args == "pending" { filter.PendingCallback = callback @@ -131,9 +143,9 @@ func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { self.logMut.Lock() defer self.logMut.Unlock() - *reply = toLogs(self.logs[id]) - - self.logs[id] = nil // empty the logs + if self.logs[id] != nil { + *reply = toLogs(self.logs[id].get()) + } return nil } @@ -331,7 +343,10 @@ func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) e args.Fn = func(msg xeth.WhisperMessage) { p.messagesMut.Lock() defer p.messagesMut.Unlock() - p.messages[id] = append(p.messages[id], msg) + 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) *reply = id @@ -342,9 +357,9 @@ func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error { self.messagesMut.Lock() defer self.messagesMut.Unlock() - *reply = self.messages[id] - - self.messages[id] = nil // empty the messages + if self.messages[id] != nil { + *reply = self.messages[id].get() + } return nil } @@ -535,3 +550,34 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error rpclogger.DebugDetailf("Reply: %T %s", reply, reply) return nil } + +var filterTickerTime = 15 * time.Second + +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) + } + } + + for id, filter := range self.messages { + if time.Since(filter.timeout) > 20*time.Second { + delete(self.messages, id) + } + } + case <-self.quit: + break done + } + } +} + +func (self *EthereumApi) stop() { + close(self.quit) +} diff --git a/rpc/packages_test.go b/rpc/packages_test.go new file mode 100644 index 0000000000..037fd78b39 --- /dev/null +++ b/rpc/packages_test.go @@ -0,0 +1,37 @@ +package rpc + +import ( + "sync" + "testing" + "time" +) + +func TestFilterClose(t *testing.T) { + api := &EthereumApi{ + logs: make(map[int]*logFilter), + messages: make(map[int]*whisperFilter), + quit: make(chan struct{}), + } + + filterTickerTime = 1 + api.logs[0] = &logFilter{} + api.messages[0] = &whisperFilter{} + var wg sync.WaitGroup + wg.Add(1) + go api.start() + go func() { + select { + case <-time.After(500 * time.Millisecond): + api.stop() + wg.Done() + } + }() + wg.Wait() + if len(api.logs) != 0 { + t.Error("expected logs to be empty") + } + + if len(api.messages) != 0 { + t.Error("expected messages to be empty") + } +} diff --git a/rpc/util.go b/rpc/util.go index 366e315ac2..29824bcdb9 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -20,10 +20,12 @@ import ( "encoding/json" "io" "net/http" + "time" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" + "github.com/ethereum/go-ethereum/xeth" ) var rpclogger = logger.NewLogger("RPC") @@ -100,3 +102,34 @@ func toLogs(logs state.Logs) (ls []Log) { return } + +type whisperFilter struct { + messages []xeth.WhisperMessage + timeout time.Time +} + +func (w *whisperFilter) add(msgs ...xeth.WhisperMessage) { + w.messages = append(w.messages, msgs...) +} +func (w *whisperFilter) get() []xeth.WhisperMessage { + w.timeout = time.Now() + tmp := w.messages + w.messages = nil + return tmp +} + +type logFilter struct { + logs state.Logs + timeout time.Time +} + +func (l *logFilter) add(logs ...state.Log) { + l.logs = append(l.logs, logs...) +} + +func (l *logFilter) get() state.Logs { + l.timeout = time.Now() + tmp := l.logs + l.logs = nil + return tmp +} diff --git a/ui/qt/clipboard/capi.hpp b/ui/qt/clipboard/capi.hpp deleted file mode 100644 index 2026134691..0000000000 --- a/ui/qt/clipboard/capi.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "clipboard.hpp" - -typedef void Clipboard_; - -Clipboard_ *initClipboard() -{ - Clipboard *clipboard = new(Clipboard); - return static_cast(clipboard); -} diff --git a/ui/qt/clipboard/clipboard.cpp b/ui/qt/clipboard/clipboard.cpp deleted file mode 100644 index 192aa7a2b9..0000000000 --- a/ui/qt/clipboard/clipboard.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "clipboard.h" - -#include - -Clipboard::Clipboard() -{ - connect(QApplication::clipboard(), &QClipboard::dataChanged, [this] { emit clipboardChanged();}); -} - -QString Clipboard::get() const -{ - QClipboard *clipboard = QApplication::clipboard(); - return clipboard->text(); -} - -void Clipboard::toClipboard(QString _text) -{ - QClipboard *clipboard = QApplicationion::clipboard(); - clipboard->setText(_text); -} diff --git a/ui/qt/clipboard/clipboard.go b/ui/qt/clipboard/clipboard.go deleted file mode 100644 index 064ee954d0..0000000000 --- a/ui/qt/clipboard/clipboard.go +++ /dev/null @@ -1,15 +0,0 @@ -package clipboard - -// #cgo CPPFLAGS: -I./ -// #cgo CXXFLAGS: -std=c++0x -pedantic-errors -Wall -fno-strict-aliasing -// #cgo LDFLAGS: -lstdc++ -// #cgo pkg-config: Qt5Quick -// -// #include "capi.hpp" -import "C" - -import "github.com/obscuren/qml" - -func SetQMLClipboard(context *qml.Context) { - context.SetVar("clipboard", (unsafe.Pointer)(C.initClipboard())) -} diff --git a/ui/qt/clipboard/clipboard.hpp b/ui/qt/clipboard/clipboard.hpp deleted file mode 100644 index 1aa213ceb1..0000000000 --- a/ui/qt/clipboard/clipboard.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -class Clipboard : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString get READ get WRITE toClipboard NOTIFY clipboardChanged) -public: - Clipboard(); - virtual ~Clipboard(){} - - Q_INVOKABLE void toClipboard(QString _text); - -signals: - void clipboardChanged(); -}; - -#ifdef __cplusplus -} // extern "C" -#endif From d8ac267f4128117c3fb9736a40f3dbc327582e32 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 14:01:30 +0100 Subject: [PATCH 33/78] dirty tracking for state objects fixed --- core/block_processor.go | 7 ++----- core/chain_manager.go | 2 +- eth/protocol.go | 2 +- state/state_object.go | 10 +++++++++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index a9795385fb..bfd9d45608 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -296,16 +296,13 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren r := new(big.Int) r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) - uncleAccount := statedb.GetAccount(uncle.Coinbase) - uncleAccount.AddAmount(r) + statedb.AddBalance(uncle.Coinbase, r) reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) } // Get the account associated with the coinbase - account := statedb.GetAccount(block.Header().Coinbase) - // Reward amount of ether to the coinbase address - account.AddAmount(reward) + statedb.AddBalance(block.Header().Coinbase, reward) return nil } diff --git a/core/chain_manager.go b/core/chain_manager.go index 003781791c..dd0dd3cbeb 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -397,7 +397,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { if chain { //self.setTransState(state.New(block.Root(), self.db)) - self.eventMux.Post(ChainEvent{block, td}) + //self.eventMux.Post(ChainEvent{block, td}) } if split { diff --git a/eth/protocol.go b/eth/protocol.go index fb694c877a..44a1184f29 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -13,7 +13,7 @@ import ( ) const ( - ProtocolVersion = 52 + ProtocolVersion = 53 NetworkId = 0 ProtocolLength = uint64(8) ProtocolMaxMsgSize = 10 * 1024 * 1024 diff --git a/state/state_object.go b/state/state_object.go index d50c9fd7a9..226c252991 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -65,7 +65,7 @@ func NewStateObject(addr []byte, db ethutil.Database) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. address := ethutil.Address(addr) - object := &StateObject{db: db, address: address, balance: new(big.Int), gasPool: new(big.Int)} + object := &StateObject{db: db, address: address, balance: new(big.Int), gasPool: new(big.Int), dirty: true} object.State = New(nil, db) //New(trie.New(ethutil.Config.Db, "")) object.storage = make(Storage) object.gasPool = new(big.Int) @@ -118,6 +118,7 @@ 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 { @@ -142,6 +143,7 @@ func (self *StateObject) GetState(k []byte) *ethutil.Value { func (self *StateObject) SetState(k []byte, value *ethutil.Value) { key := ethutil.LeftPadBytes(k, 32) self.storage[string(key)] = value.Copy() + self.dirty = true } func (self *StateObject) Sync() { @@ -166,6 +168,7 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { func (c *StateObject) AddBalance(amount *big.Int) { c.SetBalance(new(big.Int).Add(c.balance, amount)) + c.dirty = true statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.balance, amount) } @@ -180,6 +183,7 @@ func (c *StateObject) SubAmount(amount *big.Int) { c.SubBalance(amount) } func (c *StateObject) SetBalance(amount *big.Int) { c.balance = amount + c.dirty = true } func (self *StateObject) Balance() *big.Int { return self.balance } @@ -198,6 +202,8 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { c.SubAmount(total) + c.dirty = true + return nil } @@ -219,6 +225,8 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { self.AddAmount(rGas) + self.dirty = true + return nil } From ea9a549bbdc8377bca73f1417f2dc4a18396a382 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 14:19:34 +0100 Subject: [PATCH 34/78] Removed exported fields from state object and added proper set/getters --- cmd/ethtest/main.go | 4 +-- cmd/mist/ui_lib.go | 4 +-- core/state_transition.go | 8 ++--- core/transaction_pool.go | 2 +- state/dump.go | 4 +-- state/state_object.go | 67 ++++++++++++++++++++++++++-------------- state/statedb.go | 12 +++---- tests/vm/gh_test.go | 4 +-- xeth/xeth.go | 6 ++-- 9 files changed, 64 insertions(+), 47 deletions(-) diff --git a/cmd/ethtest/main.go b/cmd/ethtest/main.go index e1c4806ad6..40874616c3 100644 --- a/cmd/ethtest/main.go +++ b/cmd/ethtest/main.go @@ -51,8 +51,8 @@ func StateObjectFromAccount(db ethutil.Database, addr string, account Account) * if ethutil.IsHex(account.Code) { account.Code = account.Code[2:] } - obj.Code = ethutil.Hex2Bytes(account.Code) - obj.Nonce = ethutil.Big(account.Nonce).Uint64() + obj.SetCode(ethutil.Hex2Bytes(account.Code)) + obj.SetNonce(ethutil.Big(account.Nonce).Uint64()) return obj } diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go index 1a4d21012f..4fa6e8e55a 100644 --- a/cmd/mist/ui_lib.go +++ b/cmd/mist/ui_lib.go @@ -146,8 +146,8 @@ func (ui *UiLib) AssetPath(p string) string { func (self *UiLib) StartDbWithContractAndData(contractHash, data string) { dbWindow := NewDebuggerWindow(self) object := self.eth.ChainManager().State().GetStateObject(ethutil.Hex2Bytes(contractHash)) - if len(object.Code) > 0 { - dbWindow.SetCode(ethutil.Bytes2Hex(object.Code)) + if len(object.Code()) > 0 { + dbWindow.SetCode(ethutil.Bytes2Hex(object.Code())) } dbWindow.SetData(data) diff --git a/core/state_transition.go b/core/state_transition.go index e82be647db..36ffa23d9f 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -138,8 +138,8 @@ func (self *StateTransition) preCheck() (err error) { ) // Make sure this transaction's nonce is correct - if sender.Nonce != msg.Nonce() { - return NonceError(msg.Nonce(), sender.Nonce) + if sender.Nonce() != msg.Nonce() { + return NonceError(msg.Nonce(), sender.Nonce()) } // Pre-pay gas / Buy gas of the coinbase account @@ -166,7 +166,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { defer self.RefundGas() // Increment the nonce for the next transaction - self.state.SetNonce(sender.Address(), sender.Nonce+1) + self.state.SetNonce(sender.Address(), sender.Nonce()+1) //sender.Nonce += 1 // Transaction gas @@ -242,7 +242,7 @@ func MakeContract(msg Message, state *state.StateDB) *state.StateObject { addr := AddressFromMessage(msg) contract := state.GetOrNewStateObject(addr) - contract.InitCode = msg.Data() + contract.SetInitCode(msg.Data()) return contract } diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 894b6c440c..050cff3d8a 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -169,7 +169,7 @@ func (pool *TxPool) RemoveInvalid(query StateQuery) { for _, tx := range pool.txs { sender := query.GetAccount(tx.From()) err := pool.ValidateTransaction(tx) - if err != nil || sender.Nonce >= tx.Nonce() { + if err != nil || sender.Nonce() >= tx.Nonce() { removedTxs = append(removedTxs, tx) } } diff --git a/state/dump.go b/state/dump.go index ac646480c7..81895f1a37 100644 --- a/state/dump.go +++ b/state/dump.go @@ -30,7 +30,7 @@ func (self *StateDB) Dump() []byte { for it.Next() { stateObject := NewStateObjectFromBytes(it.Key, it.Value, self.db) - account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.Nonce, Root: ethutil.Bytes2Hex(stateObject.Root()), CodeHash: ethutil.Bytes2Hex(stateObject.codeHash)} + account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: ethutil.Bytes2Hex(stateObject.Root()), CodeHash: ethutil.Bytes2Hex(stateObject.codeHash)} account.Storage = make(map[string]string) storageIt := stateObject.State.trie.Iterator() @@ -50,7 +50,7 @@ func (self *StateDB) Dump() []byte { // Debug stuff func (self *StateObject) CreateOutputForDiff() { - fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.balance.Bytes(), self.Nonce) + fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.balance.Bytes(), self.nonce) it := self.State.trie.Iterator() for it.Next() { fmt.Printf("%x %x\n", it.Key, it.Value) diff --git a/state/state_object.go b/state/state_object.go index 226c252991..477b912a12 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -36,11 +36,11 @@ type StateObject struct { // Shared attributes balance *big.Int codeHash []byte - Nonce uint64 + nonce uint64 // Contract related attributes State *StateDB - Code Code - InitCode Code + code Code + initCode Code storage Storage @@ -89,20 +89,21 @@ func NewStateObjectFromBytes(address, data []byte, db ethutil.Database) *StateOb object := &StateObject{address: address, db: db} //object.RlpDecode(data) - object.Nonce = extobject.Nonce + object.nonce = extobject.Nonce object.balance = extobject.Balance object.codeHash = extobject.CodeHash object.State = New(extobject.Root, db) object.storage = make(map[string]*ethutil.Value) object.gasPool = new(big.Int) - object.Code, _ = db.Get(extobject.CodeHash) + object.code, _ = db.Get(extobject.CodeHash) return object } func (self *StateObject) MarkForDeletion() { self.remove = true - statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.balance) + self.dirty = true + statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.nonce, self.balance) } func (c *StateObject) getAddr(addr []byte) *ethutil.Value { @@ -159,25 +160,24 @@ func (self *StateObject) Sync() { } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { - if int64(len(c.Code)-1) < pc.Int64() { + if int64(len(c.code)-1) < pc.Int64() { return ethutil.NewValue(0) } - return ethutil.NewValueFromBytes([]byte{c.Code[pc.Int64()]}) + return ethutil.NewValueFromBytes([]byte{c.code[pc.Int64()]}) } func (c *StateObject) AddBalance(amount *big.Int) { c.SetBalance(new(big.Int).Add(c.balance, amount)) - c.dirty = true - statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.balance, amount) + statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount) } func (c *StateObject) AddAmount(amount *big.Int) { c.AddBalance(amount) } func (c *StateObject) SubBalance(amount *big.Int) { c.SetBalance(new(big.Int).Sub(c.balance, amount)) - statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.balance, amount) + statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SubBalance(amount) } @@ -186,8 +186,6 @@ func (c *StateObject) SetBalance(amount *big.Int) { c.dirty = true } -func (self *StateObject) Balance() *big.Int { return self.balance } - // // Gas setters and getters // @@ -243,12 +241,12 @@ func (self *StateObject) Copy() *StateObject { stateObject := NewStateObject(self.Address(), self.db) stateObject.balance.Set(self.balance) stateObject.codeHash = ethutil.CopyBytes(self.codeHash) - stateObject.Nonce = self.Nonce + stateObject.nonce = self.nonce if self.State != nil { stateObject.State = self.State.Copy() } - stateObject.Code = ethutil.CopyBytes(self.Code) - stateObject.InitCode = ethutil.CopyBytes(self.InitCode) + stateObject.code = ethutil.CopyBytes(self.code) + stateObject.initCode = ethutil.CopyBytes(self.initCode) stateObject.storage = self.storage.Copy() stateObject.gasPool.Set(self.gasPool) stateObject.remove = self.remove @@ -265,8 +263,12 @@ func (self *StateObject) Set(stateObject *StateObject) { // Attribute accessors // +func (self *StateObject) Balance() *big.Int { + return self.balance +} + func (c *StateObject) N() *big.Int { - return big.NewInt(int64(c.Nonce)) + return big.NewInt(int64(c.nonce)) } // Returns the address of the contract/account @@ -276,7 +278,7 @@ func (c *StateObject) Address() []byte { // Returns the initialization Code func (c *StateObject) Init() Code { - return c.InitCode + return c.initCode } func (self *StateObject) Trie() *trie.Trie { @@ -287,8 +289,27 @@ func (self *StateObject) Root() []byte { return self.Trie().Root() } +func (self *StateObject) Code() []byte { + return self.code +} + func (self *StateObject) SetCode(code []byte) { - self.Code = code + self.code = code + self.dirty = true +} + +func (self *StateObject) SetInitCode(code []byte) { + self.initCode = code + self.dirty = true +} + +func (self *StateObject) SetNonce(nonce uint64) { + self.nonce = nonce + self.dirty = true +} + +func (self *StateObject) Nonce() uint64 { + return self.nonce } // @@ -297,16 +318,16 @@ func (self *StateObject) SetCode(code []byte) { // State object encoding methods func (c *StateObject) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Nonce, c.balance, c.Root(), c.CodeHash()}) + return ethutil.Encode([]interface{}{c.nonce, c.balance, c.Root(), c.CodeHash()}) } func (c *StateObject) CodeHash() ethutil.Bytes { - return crypto.Sha3(c.Code) + return crypto.Sha3(c.code) } func (c *StateObject) RlpDecode(data []byte) { decoder := ethutil.NewValueFromBytes(data) - c.Nonce = decoder.Get(0).Uint() + c.nonce = decoder.Get(0).Uint() c.balance = decoder.Get(1).BigInt() c.State = New(decoder.Get(2).Bytes(), c.db) //New(trie.New(ethutil.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*ethutil.Value) @@ -314,7 +335,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.codeHash = decoder.Get(3).Bytes() - c.Code, _ = c.db.Get(c.codeHash) + c.code, _ = c.db.Get(c.codeHash) } // Storage change object. Used by the manifest for notifying changes to diff --git a/state/statedb.go b/state/statedb.go index 8c8a21db99..7e2b24b941 100644 --- a/state/statedb.go +++ b/state/statedb.go @@ -72,7 +72,7 @@ func (self *StateDB) AddBalance(addr []byte, amount *big.Int) { func (self *StateDB) GetNonce(addr []byte) uint64 { stateObject := self.GetStateObject(addr) if stateObject != nil { - return stateObject.Nonce + return stateObject.nonce } return 0 @@ -81,7 +81,7 @@ func (self *StateDB) GetNonce(addr []byte) uint64 { func (self *StateDB) GetCode(addr []byte) []byte { stateObject := self.GetStateObject(addr) if stateObject != nil { - return stateObject.Code + return stateObject.code } return nil @@ -99,8 +99,7 @@ func (self *StateDB) GetState(a, b []byte) []byte { func (self *StateDB) SetNonce(addr []byte, nonce uint64) { stateObject := self.GetStateObject(addr) if stateObject != nil { - stateObject.Nonce = nonce - stateObject.dirty = true + stateObject.SetNonce(nonce) } } @@ -108,7 +107,6 @@ func (self *StateDB) SetCode(addr, code []byte) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetCode(code) - stateObject.dirty = true } } @@ -116,7 +114,6 @@ func (self *StateDB) SetState(addr, key []byte, value interface{}) { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.SetState(key, ethutil.NewValue(value)) - stateObject.dirty = true } } @@ -124,7 +121,6 @@ func (self *StateDB) Delete(addr []byte) bool { stateObject := self.GetStateObject(addr) if stateObject != nil { stateObject.MarkForDeletion() - stateObject.dirty = true return true } @@ -141,7 +137,7 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() if len(stateObject.CodeHash()) > 0 { - self.db.Put(stateObject.CodeHash(), stateObject.Code) + self.db.Put(stateObject.CodeHash(), stateObject.code) } self.trie.Update(addr, stateObject.RlpEncode()) diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go index 17f9459102..2151cf9a5b 100644 --- a/tests/vm/gh_test.go +++ b/tests/vm/gh_test.go @@ -46,8 +46,8 @@ func StateObjectFromAccount(db ethutil.Database, addr string, account Account) * if ethutil.IsHex(account.Code) { account.Code = account.Code[2:] } - obj.Code = ethutil.Hex2Bytes(account.Code) - obj.Nonce = ethutil.Big(account.Nonce).Uint64() + obj.SetCode(ethutil.Hex2Bytes(account.Code)) + obj.SetNonce(ethutil.Big(account.Nonce).Uint64()) return obj } diff --git a/xeth/xeth.go b/xeth/xeth.go index d578c03c9f..67dac948c5 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -128,15 +128,15 @@ func (self *XEth) BalanceAt(addr string) string { } func (self *XEth) TxCountAt(address string) int { - return int(self.State().SafeGet(address).Nonce) + return int(self.State().SafeGet(address).Nonce()) } func (self *XEth) CodeAt(address string) string { - return toHex(self.State().SafeGet(address).Code) + return toHex(self.State().SafeGet(address).Code()) } func (self *XEth) IsContract(address string) bool { - return len(self.State().SafeGet(address).Code) > 0 + return len(self.State().SafeGet(address).Code()) > 0 } func (self *XEth) SecretToAddress(key string) string { From e282ad25a83e93f7a5ac085e3580ee9051daad10 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 15:24:19 +0100 Subject: [PATCH 35/78] eth: add poc-8.ethdev.com as second default bootstrap node --- eth/backend.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth/backend.go b/eth/backend.go index b57e9fd69e..f060ec3b68 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -25,7 +25,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"), } ) From e968928613a5d49ad67e921a52883268d4ad74d1 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 20 Feb 2015 15:26:50 +0100 Subject: [PATCH 36/78] eth: persist node key between sessions (#304) --- eth/backend.go | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index f060ec3b68..0e5d244297 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -3,6 +3,8 @@ package eth import ( "crypto/ecdsa" "fmt" + "io/ioutil" + "path" "strings" "github.com/ethereum/go-ethereum/core" @@ -80,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 @@ -164,18 +187,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, From 66d5559866f37a79a7b5aeccd03dfe1b4401542b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 16:59:08 +0100 Subject: [PATCH 37/78] Fixed chain event issue --- core/chain_manager.go | 4 +--- rpc/packages.go | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/core/chain_manager.go b/core/chain_manager.go index 47cad825d3..600dc3db51 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -396,9 +396,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.mu.Unlock() if chain { - fmt.Println("POST START") - self.eventMux.Post(ChainEvent{block, td}) - fmt.Println("POST END") + go self.eventMux.Post(ChainEvent{block, td}) } if split { diff --git a/rpc/packages.go b/rpc/packages.go index 56c1751d79..72e090130f 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -101,13 +101,11 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro self.logMut.Lock() defer self.logMut.Unlock() - if self.logs[id] == nil { - self.logs[id] = &logFilter{timeout: time.Now()} - } - self.logs[id].add(logs...) } id = self.filterManager.InstallFilter(filter) + self.logs[id] = &logFilter{timeout: time.Now()} + *reply = id return nil From cc43ab9a810125239636143a91609389b19b49c7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 18:05:46 +0100 Subject: [PATCH 38/78] Minor updates for release --- cmd/ethereum/main.go | 2 +- cmd/mist/assets/qml/main.qml | 2 +- cmd/mist/main.go | 2 +- core/chain_manager.go | 3 ++- core/genesis.go | 44 +++++++++++++++++++++++++----------- eth/protocol.go | 2 +- ethutil/common_test.go | 2 +- miner/worker.go | 2 -- 8 files changed, 38 insertions(+), 21 deletions(-) diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 1f1a0b7613..fcf7f8ef01 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -37,7 +37,7 @@ import ( const ( ClientIdentifier = "Ethereum(G)" - Version = "0.8.3" + Version = "0.9.0" ) var clilogger = logger.NewLogger("CLI") diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index 937670bd2a..c421d696cb 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -964,7 +964,7 @@ ApplicationWindow { anchors.top: parent.top anchors.topMargin: 30 font.pointSize: 12 - text: "

Mist (0.7.10)


Development

Jeffrey Wilcke
Viktor Trón
Felix Lange
Taylor Gerring
Daniel Nagy

UX

Alex van de Sande
" + text: "

Mist (0.9.0)


Development

Jeffrey Wilcke
Viktor Trón
Felix Lange
Taylor Gerring
Daniel Nagy
Gustav Simonsson

UX/UI

Alex van de Sande
Fabian Vogelsteller" } } diff --git a/cmd/mist/main.go b/cmd/mist/main.go index d41aa34bf3..c7152347d5 100644 --- a/cmd/mist/main.go +++ b/cmd/mist/main.go @@ -36,7 +36,7 @@ import ( const ( ClientIdentifier = "Mist" - Version = "0.8.3" + Version = "0.9.0" ) var ethereum *eth.Ethereum diff --git a/core/chain_manager.go b/core/chain_manager.go index 600dc3db51..9ef091c3cf 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -268,6 +268,7 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain break } } + fmt.Printf("get hash %x (%d)\n", hash, len(chain)) return } @@ -396,7 +397,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.mu.Unlock() if chain { - go self.eventMux.Post(ChainEvent{block, td}) + self.eventMux.Post(ChainEvent{block, td}) } if split { diff --git a/core/genesis.go b/core/genesis.go index c870ce61e1..75b4fc100d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -1,7 +1,10 @@ package core import ( + "encoding/json" + "fmt" "math/big" + "os" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -31,24 +34,39 @@ func GenesisBlock(db ethutil.Database) *types.Block { genesis.SetTransactions(types.Transactions{}) genesis.SetReceipts(types.Receipts{}) + var accounts map[string]struct{ Balance string } + err := json.Unmarshal(genesisData, &accounts) + if err != nil { + fmt.Println("enable to decode genesis json data:", err) + os.Exit(1) + } + statedb := state.New(genesis.Root(), db) - for _, addr := range []string{ - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6", - "e4157b34ea9615cfbde6b4fda419828124b70c78", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - } { + for addr, account := range accounts { codedAddr := ethutil.Hex2Bytes(addr) - account := statedb.GetAccount(codedAddr) - account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) - statedb.UpdateStateObject(account) + accountState := statedb.GetAccount(codedAddr) + accountState.SetBalance(ethutil.Big(account.Balance)) + statedb.UpdateStateObject(accountState) } statedb.Sync() genesis.Header().Root = statedb.Root() + fmt.Printf("+++ genesis +++\nRoot: %x\nHash: %x\n", genesis.Header().Root, genesis.Hash()) + return genesis } + +var genesisData = []byte(`{ + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": {"balance": "154162184000000000000000"}, + "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": {"balance": "102774789000000000000000"}, + "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": {"balance": "51387394000000000000000"}, + "b7576e9d314df41ec5506494293afb1bd5d3f65d": {"balance": "69423399000000000000000"} +}`) diff --git a/eth/protocol.go b/eth/protocol.go index 44a1184f29..8221c1b296 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -13,7 +13,7 @@ import ( ) const ( - ProtocolVersion = 53 + ProtocolVersion = 54 NetworkId = 0 ProtocolLength = uint64(8) ProtocolMaxMsgSize = 10 * 1024 * 1024 diff --git a/ethutil/common_test.go b/ethutil/common_test.go index c2b6077e9b..aa30f311af 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -39,7 +39,7 @@ func (s *CommonSuite) TestCommon(c *checker.C) { douglas := CurrencyToString(BigPow(10, 43)) einstein := CurrencyToString(BigPow(10, 22)) ether := CurrencyToString(BigPow(10, 19)) - finney := CurrencyToString(BigPow(10, 16)) + finney := CurrencyToString(BigPow(10, 15)) szabo := CurrencyToString(BigPow(10, 13)) shannon := CurrencyToString(BigPow(10, 10)) babbage := CurrencyToString(BigPow(10, 7)) diff --git a/miner/worker.go b/miner/worker.go index aea5cc5351..1f3a52ab52 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -117,11 +117,9 @@ out: case event := <-events.Chan(): switch ev := event.(type) { case core.ChainEvent: - println("miner start") if self.current.block != ev.Block { self.commitNewWork() } - println("miner end") case core.NewMinedBlockEvent: self.commitNewWork() } From 9feb657763b85cd5beece82efc9e6477235b7d67 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 18:06:45 +0100 Subject: [PATCH 39/78] Turbo off --- pow/ezp/pow.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pow/ezp/pow.go b/pow/ezp/pow.go index f4a8b80e5e..540381243f 100644 --- a/pow/ezp/pow.go +++ b/pow/ezp/pow.go @@ -21,7 +21,7 @@ type EasyPow struct { } func New() *EasyPow { - return &EasyPow{turbo: true} + return &EasyPow{turbo: false} } func (pow *EasyPow) GetHashrate() int64 { From d586a633ff005ac01c9f1eb33552d147cf6c883e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 18:13:39 +0100 Subject: [PATCH 40/78] Updated readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6dd2182ded..3f7329a476 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ Ethereum Go Client © 2014 Jeffrey Wilcke. - | Linux | OSX | Windows -----------|---------|-----|-------- -develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](http://build.ethdev.com/builders/Linux%20Go%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](http://build.ethdev.com/builders/OSX%20Go%20develop%20branch/builds/-1) | N/A -master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20master%20branch)](http://build.ethdev.com/builders/Linux%20Go%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20Go%20master%20branch)](http://build.ethdev.com/builders/OSX%20Go%20master%20branch/builds/-1) | N/A + | Linux | OSX | Windows | Tests +----------|---------|-----|---------|------ +develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](http://build.ethdev.com/builders/Linux%20Go%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](http://build.ethdev.com/builders/OSX%20Go%20develop%20branch/builds/-1) | N/A | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=develop)](https://travis-ci.org/ethereum/go-ethereum) +master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20master%20branch)](http://build.ethdev.com/builders/Linux%20Go%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20Go%20master%20branch)](http://build.ethdev.com/builders/OSX%20Go%20master%20branch/builds/-1) | N/A | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) [![Bugs](https://badge.waffle.io/ethereum/go-ethereum.png?label=bug&title=Bugs)](https://waffle.io/ethereum/go-ethereum) [![Stories in Ready](https://badge.waffle.io/ethereum/go-ethereum.png?label=ready&title=Ready)](https://waffle.io/ethereum/go-ethereum) From 113cf4208b279eb3d7abd4daadb64da221a95554 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Fri, 20 Feb 2015 20:52:03 +0100 Subject: [PATCH 41/78] Update build status links to https --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f7329a476..18392816a2 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Ethereum Go Client © 2014 Jeffrey Wilcke. | Linux | OSX | Windows | Tests ----------|---------|-----|---------|------ -develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](http://build.ethdev.com/builders/Linux%20Go%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](http://build.ethdev.com/builders/OSX%20Go%20develop%20branch/builds/-1) | N/A | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=develop)](https://travis-ci.org/ethereum/go-ethereum) -master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20master%20branch)](http://build.ethdev.com/builders/Linux%20Go%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20Go%20master%20branch)](http://build.ethdev.com/builders/OSX%20Go%20master%20branch/builds/-1) | N/A | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) +develop | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](https://build.ethdev.com/builders/Linux%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](https://build.ethdev.com/builders/OSX%20Go%20develop%20branch/builds/-1) | N/A | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=develop)](https://travis-ci.org/ethereum/go-ethereum) +master | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20master%20branch)](https://build.ethdev.com/builders/Linux%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20Go%20master%20branch)](https://build.ethdev.com/builders/OSX%20Go%20master%20branch/builds/-1) | N/A | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) [![Bugs](https://badge.waffle.io/ethereum/go-ethereum.png?label=bug&title=Bugs)](https://waffle.io/ethereum/go-ethereum) [![Stories in Ready](https://badge.waffle.io/ethereum/go-ethereum.png?label=ready&title=Ready)](https://waffle.io/ethereum/go-ethereum) From f9663b8f4f0af5dd456c3dd9682d86912091204b Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Fri, 20 Feb 2015 20:57:45 +0100 Subject: [PATCH 42/78] Fix test for Finney --- ethutil/common_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/common_test.go b/ethutil/common_test.go index aa30f311af..c2b6077e9b 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -39,7 +39,7 @@ func (s *CommonSuite) TestCommon(c *checker.C) { douglas := CurrencyToString(BigPow(10, 43)) einstein := CurrencyToString(BigPow(10, 22)) ether := CurrencyToString(BigPow(10, 19)) - finney := CurrencyToString(BigPow(10, 15)) + finney := CurrencyToString(BigPow(10, 16)) szabo := CurrencyToString(BigPow(10, 13)) shannon := CurrencyToString(BigPow(10, 10)) babbage := CurrencyToString(BigPow(10, 7)) From 92337baa5a51f4d4ec39cb5004bdcc4b07d321e0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Feb 2015 00:42:57 +0100 Subject: [PATCH 43/78] reverted back to proper version number --- cmd/ethereum/main.go | 2 +- cmd/mist/assets/qml/main.qml | 2 +- cmd/mist/main.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index fcf7f8ef01..53a558a99c 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -37,7 +37,7 @@ import ( const ( ClientIdentifier = "Ethereum(G)" - Version = "0.9.0" + Version = "0.8.4" ) var clilogger = logger.NewLogger("CLI") diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index c421d696cb..ca37dbf3c3 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -964,7 +964,7 @@ ApplicationWindow { anchors.top: parent.top anchors.topMargin: 30 font.pointSize: 12 - text: "

Mist (0.9.0)


Development

Jeffrey Wilcke
Viktor Trón
Felix Lange
Taylor Gerring
Daniel Nagy
Gustav Simonsson

UX/UI

Alex van de Sande
Fabian Vogelsteller" + text: "

Mist (0.8.4)


Development

Jeffrey Wilcke
Viktor Trón
Felix Lange
Taylor Gerring
Daniel Nagy
Gustav Simonsson

UX/UI

Alex van de Sande
Fabian Vogelsteller" } } diff --git a/cmd/mist/main.go b/cmd/mist/main.go index c7152347d5..45eddeb283 100644 --- a/cmd/mist/main.go +++ b/cmd/mist/main.go @@ -36,7 +36,7 @@ import ( const ( ClientIdentifier = "Mist" - Version = "0.9.0" + Version = "0.8.4" ) var ethereum *eth.Ethereum From cb7cd0391992e1800e25e1dc049c5d64a5432fe4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Feb 2015 00:53:27 +0100 Subject: [PATCH 44/78] unlock mutex --- rpc/packages.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rpc/packages.go b/rpc/packages.go index 72e090130f..aed43cae2b 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -617,6 +617,8 @@ done: delete(self.messages, id) } } + self.logMut.Unlock() + self.messagesMut.Unlock() case <-self.quit: break done } From fd3793b8cf04e2ca78b9c0a01844a09aa25b91e9 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Sat, 21 Feb 2015 05:33:51 +0100 Subject: [PATCH 45/78] Correct stack size validation for MUL, CALLDATACOPY, EXTCODESIZE, BLOCKHASH --- vm/vm.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/vm.go b/vm/vm.go index 5ec507ddc6..bb293eb9bc 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -779,9 +779,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) @@ -859,7 +859,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]) From d8f7cb2f55e7e8cf1c831b65e8962bb0bdd2599e Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Sat, 21 Feb 2015 13:48:09 +0100 Subject: [PATCH 46/78] Don't print per-function testing results --- .travis.yml | 5 +++++ gocoverage.sh | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1b31048267..5499cf2571 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,15 @@ before_install: - sudo apt-get update -qq - sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine install: + # - go get code.google.com/p/go.tools/cmd/goimports + # - go get github.com/golang/lint/golint # - go get golang.org/x/tools/cmd/vet - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi - go get github.com/mattn/goveralls before_script: + # - gofmt -l -w . + # - goimports -l -w . + # - golint . # - go vet ./... # - go test -race ./... script: diff --git a/gocoverage.sh b/gocoverage.sh index e54a5cab03..5479d8d3b7 100755 --- a/gocoverage.sh +++ b/gocoverage.sh @@ -29,6 +29,3 @@ if ls $dir/*.go &> /dev/null; then fi fi done - -go tool cover -func profile.cov - From 483d96a89d68023360d211ab329400f4b960fe48 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 22 Feb 2015 13:12:01 +0100 Subject: [PATCH 47/78] Added eth_logs & fixed issue with manual log filtering * Implemented `eth_logs` * Fixed issue with `filter.Find()` where logs were appended to an incorrect, non-returned slice resulting in no logs found --- cmd/mist/assets/examples/coin.html | 23 +++++++++++------------ cmd/utils/cmd.go | 2 +- core/block_processor.go | 16 ++++++---------- core/filter.go | 5 ++--- rpc/packages.go | 15 +++++++++++++++ xeth/xeth.go | 12 +++++------- 6 files changed, 40 insertions(+), 33 deletions(-) diff --git a/cmd/mist/assets/examples/coin.html b/cmd/mist/assets/examples/coin.html index cb9d471de5..18a6811d73 100644 --- a/cmd/mist/assets/examples/coin.html +++ b/cmd/mist/assets/examples/coin.html @@ -14,8 +14,9 @@
- Amount: + Address: + Amount:
@@ -58,7 +59,7 @@ }], "outputs": [] }, { - "name":"received", + "name":"Changed", "type":"event", "inputs": [ {"name":"from","type":"address","indexed":true}, @@ -69,18 +70,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,7 +90,7 @@ var storage = eth.storageAt(address); table.innerHTML = ""; for( var item in storage ) { - table.innerHTML += ""+item.toUpperCase()+""+web3.toDecimal(storage[item])+""; + table.innerHTML += ""+item+""+web3.toDecimal(storage[item])+""; } } @@ -106,6 +103,7 @@ } var value = parseInt( document.querySelector("#amount").value ); + console.log("transact: ", to, " => ", value) contract.send( to, value ); } @@ -121,7 +119,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 +127,8 @@ contract JevCoin { balances[msg.sender] -= value; balances[to] += value; - changed(msg.sender, to); + Changed(msg.sender, value); + Changed(to, value); } function balance(address who) constant returns(uint t) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index d252f3ab24..bc8fafafb2 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -272,7 +272,7 @@ func BlockDo(ethereum *eth.Ethereum, hash []byte) error { parent := ethereum.ChainManager().GetBlock(block.ParentHash()) statedb := state.New(parent.Root(), ethereum.Db()) - _, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block) + _, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block, true) if err != nil { return err } diff --git a/core/block_processor.go b/core/block_processor.go index bfd9d45608..fd591a29d8 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -60,12 +60,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)) // 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 +100,9 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated // Notify all subscribers if !transientProcess { go self.eventMux.Post(TxPostEvent{tx}) + go self.eventMux.Post(statedb.Logs()) } - 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 } @@ -316,13 +315,10 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro var ( parent = sm.bc.GetBlock(block.Header().ParentHash) - //state = state.New(parent.Trie().Copy()) - state = state.New(parent.Root(), sm.db) + state = state.New(parent.Root(), sm.db) ) - defer state.Reset() - - sm.TransitionState(state, parent, block) + sm.TransitionState(state, parent, block, true) sm.AccumulateRewards(state, block, parent) return state.Logs(), nil diff --git a/core/filter.go b/core/filter.go index 88f12a67c0..cdf7b282d3 100644 --- a/core/filter.go +++ b/core/filter.go @@ -111,14 +111,14 @@ func (self *Filter) Find() state.Logs { // current parameters if self.bloomFilter(block) { // Get the logs of the block - logs, err := self.eth.BlockProcessor().GetLogs(block) + unfiltered, err := self.eth.BlockProcessor().GetLogs(block) if err != nil { chainlogger.Warnln("err: filter get logs ", err) break } - logs = append(logs, self.FilterLogs(logs)...) + logs = append(logs, self.FilterLogs(unfiltered)...) } block = self.eth.ChainManager().GetBlock(block.ParentHash()) @@ -146,7 +146,6 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs { Logs: for _, log := range logs { if !includes(self.address, log.Address()) { - //if !bytes.Equal(self.address, log.Address()) { continue } diff --git a/rpc/packages.go b/rpc/packages.go index aed43cae2b..b51bde7ce0 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -167,6 +167,15 @@ func (self *EthereumApi) Logs(id int, reply *interface{}) error { return nil } +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 +} + func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { err := args.requirements() if err != nil { @@ -509,6 +518,12 @@ 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 return nil diff --git a/xeth/xeth.go b/xeth/xeth.go index f3569e4549..5907a83296 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -288,13 +288,11 @@ func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string) //fmt.Printf("create tx: %x %v\n", tx.Hash()[:4], tx.Nonce()) - /* - // Do some pre processing for our "pre" events and hooks - block := self.chainManager.NewBlock(key.Address()) - coinbase := state.GetOrNewStateObject(key.Address()) - coinbase.SetGasPool(block.GasLimit()) - self.blockProcessor.ApplyTransactions(coinbase, state, block, types.Transactions{tx}, true) - */ + // Do some pre processing for our "pre" events and hooks + block := self.chainManager.NewBlock(key.Address()) + coinbase := state.GetOrNewStateObject(key.Address()) + coinbase.SetGasPool(block.GasLimit()) + self.blockProcessor.ApplyTransactions(coinbase, state, block, types.Transactions{tx}, true) err = self.eth.TxPool().Add(tx) if err != nil { From bba85a207488d27819dc6f6f5758b80947ea200b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 22 Feb 2015 13:24:26 +0100 Subject: [PATCH 48/78] Added Number to logs --- rpc/util.go | 2 ++ state/log.go | 11 +++++++++-- vm/environment.go | 5 +++++ vm/vm.go | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/rpc/util.go b/rpc/util.go index 29824bcdb9..1939b34749 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -84,6 +84,7 @@ type Log struct { Address string `json:"address"` Topic []string `json:"topics"` 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) } diff --git a/state/log.go b/state/log.go index 46360f4aae..d503bd1a07 100644 --- a/state/log.go +++ b/state/log.go @@ -12,16 +12,19 @@ type Log interface { Address() []byte Topics() [][]byte Data() []byte + + Number() uint64 } type StateLog struct { address []byte topics [][]byte data []byte + number uint64 } -func NewLog(address []byte, topics [][]byte, data []byte) *StateLog { - return &StateLog{address, topics, data} +func NewLog(address []byte, topics [][]byte, data []byte, number uint64) *StateLog { + return &StateLog{address, topics, data, number} } func (self *StateLog) Address() []byte { @@ -36,6 +39,10 @@ func (self *StateLog) Data() []byte { return self.data } +func (self *StateLog) Number() uint64 { + return self.number +} + func NewLogFromValue(decoder *ethutil.Value) *StateLog { log := &StateLog{ address: decoder.Get(0).Bytes(), diff --git a/vm/environment.go b/vm/environment.go index 8507e248f8..5b4d6c8f0a 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -54,6 +54,7 @@ type Log struct { address []byte topics [][]byte data []byte + log uint64 } func (self *Log) Address() []byte { @@ -68,6 +69,10 @@ func (self *Log) Data() []byte { return self.data } +func (self *Log) Number() uint64 { + return self.log +} + func (self *Log) RlpData() interface{} { return []interface{}{self.address, ethutil.ByteSliceToInterface(self.topics), self.data} } diff --git a/vm/vm.go b/vm/vm.go index 5ec507ddc6..b20d7b6030 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -578,7 +578,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I } data := mem.Get(mStart.Int64(), mSize.Int64()) - log := &Log{context.Address(), topics, data} + log := &Log{context.Address(), topics, data, self.env.BlockNumber().Uint64()} self.env.AddLog(log) self.Printf(" => %v", log) From 321dce1f47135f673730cb86fdf1faf03dc6cbd4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 22 Feb 2015 13:26:10 +0100 Subject: [PATCH 49/78] Bump --- cmd/ethereum/main.go | 2 +- cmd/mist/assets/qml/main.qml | 2 +- cmd/mist/main.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 53a558a99c..9c840de589 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -37,7 +37,7 @@ import ( const ( ClientIdentifier = "Ethereum(G)" - Version = "0.8.4" + Version = "0.8.5" ) var clilogger = logger.NewLogger("CLI") diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index ca37dbf3c3..e80bd87e09 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -964,7 +964,7 @@ ApplicationWindow { anchors.top: parent.top anchors.topMargin: 30 font.pointSize: 12 - text: "

Mist (0.8.4)


Development

Jeffrey Wilcke
Viktor Trón
Felix Lange
Taylor Gerring
Daniel Nagy
Gustav Simonsson

UX/UI

Alex van de Sande
Fabian Vogelsteller" + text: "

Mist (0.8.5)


Development

Jeffrey Wilcke
Viktor Trón
Felix Lange
Taylor Gerring
Daniel Nagy
Gustav Simonsson

UX/UI

Alex van de Sande
Fabian Vogelsteller" } } diff --git a/cmd/mist/main.go b/cmd/mist/main.go index 45eddeb283..ad6eb5becb 100644 --- a/cmd/mist/main.go +++ b/cmd/mist/main.go @@ -36,7 +36,7 @@ import ( const ( ClientIdentifier = "Mist" - Version = "0.8.4" + Version = "0.8.5" ) var ethereum *eth.Ethereum From 40adb7feb657cd1cb2e4c7a02c8a9db95b18e67c Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 23 Feb 2015 11:28:20 +0100 Subject: [PATCH 50/78] Implement OS sensitive dataDirs --- accounts/accounts_test.go | 3 ++- cmd/ethereum/flags.go | 11 +++-------- cmd/mist/flags.go | 10 +++------- crypto/key_store_plain.go | 7 ------- crypto/key_store_test.go | 9 +++++---- ethutil/common.go | 12 ++++++++++++ 6 files changed, 25 insertions(+), 27 deletions(-) diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go index 30e8c62855..127334404f 100644 --- a/accounts/accounts_test.go +++ b/accounts/accounts_test.go @@ -5,10 +5,11 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/randentropy" + "github.com/ethereum/go-ethereum/ethutil" ) func TestAccountManager(t *testing.T) { - ks := crypto.NewKeyStorePlain(crypto.DefaultDataDir()) + ks := crypto.NewKeyStorePlain(ethutil.DefaultDataDir()) am := NewAccountManager(ks) pass := "" // not used but required by API a1, err := am.NewAccount(pass) diff --git a/cmd/ethereum/flags.go b/cmd/ethereum/flags.go index 577bee4426..7d410c8e45 100644 --- a/cmd/ethereum/flags.go +++ b/cmd/ethereum/flags.go @@ -26,10 +26,10 @@ import ( "fmt" "log" "os" - "os/user" "path" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/vm" @@ -79,12 +79,7 @@ var ( InputFile string ) -func defaultDataDir() string { - usr, _ := user.Current() - return path.Join(usr.HomeDir, ".ethereum") -} - -var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini") +var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini") func Init() { // TODO: move common flag processing to cmd/util @@ -107,7 +102,7 @@ func Init() { flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)") flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given") flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") - flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use") + flag.StringVar(&Datadir, "datadir", ethutil.DefaultDataDir(), "specifies the datadir to use") flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") diff --git a/cmd/mist/flags.go b/cmd/mist/flags.go index d9487de9e0..d5ed60a211 100644 --- a/cmd/mist/flags.go +++ b/cmd/mist/flags.go @@ -26,13 +26,13 @@ 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" @@ -94,12 +94,8 @@ func defaultAssetPath() string { } 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,7 +117,7 @@ func Init() { flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)") flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given") flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") - flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use") + flag.StringVar(&Datadir, "datadir", ethutil.DefaultDataDir(), "specifies the datadir to use") flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") diff --git a/crypto/key_store_plain.go b/crypto/key_store_plain.go index 6b76962a0b..255ae0ed72 100644 --- a/crypto/key_store_plain.go +++ b/crypto/key_store_plain.go @@ -30,7 +30,6 @@ import ( "io" "io/ioutil" "os" - "os/user" "path" ) @@ -48,12 +47,6 @@ type keyStorePlain struct { keysDirPath string } -// TODO: copied from cmd/ethereum/flags.go -func DefaultDataDir() string { - usr, _ := user.Current() - return path.Join(usr.HomeDir, ".ethereum") -} - func NewKeyStorePlain(path string) KeyStore2 { return &keyStorePlain{path} } diff --git a/crypto/key_store_test.go b/crypto/key_store_test.go index 485d8f5367..11531d4601 100644 --- a/crypto/key_store_test.go +++ b/crypto/key_store_test.go @@ -2,12 +2,13 @@ package crypto import ( "github.com/ethereum/go-ethereum/crypto/randentropy" + "github.com/ethereum/go-ethereum/ethutil" "reflect" "testing" ) func TestKeyStorePlain(t *testing.T) { - ks := NewKeyStorePlain(DefaultDataDir()) + ks := NewKeyStorePlain(ethutil.DefaultDataDir()) pass := "" // not used but required by API k1, err := ks.GenerateNewKey(randentropy.Reader, pass) if err != nil { @@ -35,7 +36,7 @@ func TestKeyStorePlain(t *testing.T) { } func TestKeyStorePassphrase(t *testing.T) { - ks := NewKeyStorePassphrase(DefaultDataDir()) + ks := NewKeyStorePassphrase(ethutil.DefaultDataDir()) pass := "foo" k1, err := ks.GenerateNewKey(randentropy.Reader, pass) if err != nil { @@ -61,7 +62,7 @@ func TestKeyStorePassphrase(t *testing.T) { } func TestKeyStorePassphraseDecryptionFail(t *testing.T) { - ks := NewKeyStorePassphrase(DefaultDataDir()) + ks := NewKeyStorePassphrase(ethutil.DefaultDataDir()) pass := "foo" k1, err := ks.GenerateNewKey(randentropy.Reader, pass) if err != nil { @@ -89,7 +90,7 @@ func TestImportPreSaleKey(t *testing.T) { // python pyethsaletool.py genwallet // with password "foo" fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}" - ks := NewKeyStorePassphrase(DefaultDataDir()) + ks := NewKeyStorePassphrase(ethutil.DefaultDataDir()) pass := "foo" _, err := ImportPreSaleKey(ks, []byte(fileContent), pass) if err != nil { diff --git a/ethutil/common.go b/ethutil/common.go index 2ef2440c78..efc519732c 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -3,10 +3,22 @@ package ethutil import ( "fmt" "math/big" + "os/user" + "path" "runtime" "time" ) +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" } From 6fd894aae00c8c0f9f33eae7353dd9afd97f4fa1 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Mon, 23 Feb 2015 11:54:23 +0100 Subject: [PATCH 51/78] Allow zero and negative block numbers 0 is genesis block. Xeth recognises -1 as current --- rpc/args.go | 7 ------- rpc/packages.go | 12 ++++-------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/rpc/args.go b/rpc/args.go index f730819fd9..347f604109 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -22,13 +22,6 @@ func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) { 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 -} - type NewTxArgs struct { From string `json:"from"` To string `json:"to"` diff --git a/rpc/packages.go b/rpc/packages.go index b51bde7ce0..2f694b823f 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -177,15 +177,11 @@ func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error } func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { - err := args.requirements() - if err != nil { - return err - } - - if args.BlockNumber > 0 { - *reply = p.xeth.BlockByNumber(args.BlockNumber) - } else { + // 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.BlockByNumber(args.BlockNumber) } return nil } From b2a225a52e45315f3ec90e11707fefa6059d13f5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Feb 2015 15:43:41 +0100 Subject: [PATCH 52/78] Properly uninstall filters. Mining issue fixed #closes #365 * Added an additional tx state which is used to get the current nonce * Refresh transient state each time a new canonical block is found * Properly uninstall filters. Fixes a possible crash in RPC --- cmd/mist/assets/examples/coin.html | 24 ++++++++++++++++++------ core/chain_manager.go | 30 ++++++++++++++++++++++++++---- rpc/packages.go | 11 ++++------- rpc/util.go | 2 ++ whisper/whisper.go | 4 ++++ xeth/xeth.go | 10 +++++----- 6 files changed, 59 insertions(+), 22 deletions(-) diff --git a/cmd/mist/assets/examples/coin.html b/cmd/mist/assets/examples/coin.html index 18a6811d73..509a9aeeb3 100644 --- a/cmd/mist/assets/examples/coin.html +++ b/cmd/mist/assets/examples/coin.html @@ -19,6 +19,7 @@ Amount: +
@@ -95,17 +96,28 @@ } function transact() { - var to = document.querySelector("#address").value; - if( to.length == 0 ) { + var to = document.querySelector("#address"); + if( to.value.length == 0 ) { to = "0x4205b06c2cfa0e30359edcab94543266cb6fa1d3"; } else { - to = "0x"+to; + if (to.value.substr(0,2) != "0x") + to.value = "0x"+to.value; } - var value = parseInt( document.querySelector("#amount").value ); - console.log("transact: ", to, " => ", value) + var value = document.querySelector("#amount"); + var amount = parseInt( value.value ); + console.log("transact: ", to.value, " => ", amount) - contract.send( to, value ); + contract.send( to.value, amount ); + + to.value = ""; + value.value = ""; + + var message = document.querySelector("#message") + message.innerHTML = "Submitted"; + setTimeout(function() { + message.innerHTML = ""; + }, 1000); } refresh(); diff --git a/core/chain_manager.go b/core/chain_manager.go index 9ef091c3cf..4c7db6e2e3 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -85,12 +85,14 @@ type ChainManager struct { lastBlockHash []byte transState *state.StateDB + txState *state.StateDB } func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager { bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux} bc.setLastBlock() bc.transState = bc.State().Copy() + bc.txState = bc.State().Copy() return bc } @@ -138,6 +140,19 @@ func (self *ChainManager) TransState() *state.StateDB { return self.transState } +func (self *ChainManager) TxState() *state.StateDB { + self.tsmu.RLock() + defer self.tsmu.RUnlock() + + return self.txState +} + +func (self *ChainManager) setTxState(state *state.StateDB) { + self.tsmu.Lock() + defer self.tsmu.Unlock() + self.txState = state +} + func (self *ChainManager) setTransState(statedb *state.StateDB) { self.transState = statedb } @@ -363,6 +378,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 +394,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 +412,18 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.setTotalDifficulty(td) self.insert(block) - chain = true + canonical = true } } self.mu.Unlock() - if chain { + if canonical { + self.setTransState(state.New(block.Root(), self.db)) self.eventMux.Post(ChainEvent{block, td}) } if split { - self.setTransState(state.New(block.Root(), self.db)) + self.setTxState(state.New(block.Root(), self.db)) self.eventMux.Post(ChainSplitEvent{block}) } } diff --git a/rpc/packages.go b/rpc/packages.go index b51bde7ce0..571f3a3000 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -126,10 +126,6 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error 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 +135,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 @@ -377,12 +374,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) + p.messages[id] = &whisperFilter{timeout: time.Now()} *reply = id return nil } @@ -623,12 +618,14 @@ done: 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) } } diff --git a/rpc/util.go b/rpc/util.go index 1939b34749..00a418783a 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -108,6 +108,7 @@ func toLogs(logs state.Logs) (ls []Log) { type whisperFilter struct { messages []xeth.WhisperMessage timeout time.Time + id int } func (w *whisperFilter) add(msgs ...xeth.WhisperMessage) { @@ -123,6 +124,7 @@ func (w *whisperFilter) get() []xeth.WhisperMessage { type logFilter struct { logs state.Logs timeout time.Time + id int } func (l *logFilter) add(logs ...state.Log) { diff --git a/whisper/whisper.go b/whisper/whisper.go index 50c2f98fd2..13209f9a6e 100644 --- a/whisper/whisper.go +++ b/whisper/whisper.go @@ -127,6 +127,10 @@ func (self *Whisper) Watch(opts Filter) int { }) } +func (self *Whisper) Unwatch(id int) { + self.filters.Uninstall(id) +} + func (self *Whisper) Messages(id int) (messages []*Message) { filter := self.filters.Get(id) if filter != nil { diff --git a/xeth/xeth.go b/xeth/xeth.go index 5907a83296..2985ce982e 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -277,7 +277,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()) } @@ -289,10 +289,10 @@ 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 { From 0b57bad2de08f382c1b36045db4c66b84d207d3b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Feb 2015 19:25:41 +0100 Subject: [PATCH 53/78] removed log --- core/chain_manager.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/chain_manager.go b/core/chain_manager.go index 9ef091c3cf..38d1d64b4c 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -268,7 +268,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain break } } - fmt.Printf("get hash %x (%d)\n", hash, len(chain)) return } From 7c510109cdcd6251724df6c7705b27043c3168f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Feb 2015 20:27:00 +0100 Subject: [PATCH 54/78] skipping test --- event/filter/eth_filter.go | 3 --- rpc/packages_test.go | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/event/filter/eth_filter.go b/event/filter/eth_filter.go index 73d2cd9358..4ba66a7e07 100644 --- a/event/filter/eth_filter.go +++ b/event/filter/eth_filter.go @@ -3,7 +3,6 @@ package filter // TODO make use of the generic filtering system import ( - "fmt" "sync" "github.com/ethereum/go-ethereum/core" @@ -75,7 +74,6 @@ out: case event := <-events.Chan(): switch event := event.(type) { case core.ChainEvent: - fmt.Println("filter start") self.filterMu.RLock() for _, filter := range self.filters { if filter.BlockCallback != nil { @@ -83,7 +81,6 @@ out: } } self.filterMu.RUnlock() - fmt.Println("filter stop") case core.PendingBlockEvent: self.filterMu.RLock() diff --git a/rpc/packages_test.go b/rpc/packages_test.go index 037fd78b39..a9fc16cd37 100644 --- a/rpc/packages_test.go +++ b/rpc/packages_test.go @@ -7,6 +7,7 @@ import ( ) func TestFilterClose(t *testing.T) { + t.Skip() api := &EthereumApi{ logs: make(map[int]*logFilter), messages: make(map[int]*whisperFilter), From 4142708d9d30a38c3071b895b2c42f8723830fb1 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 24 Feb 2015 08:51:58 +0100 Subject: [PATCH 55/78] Convert gas values to integers Fixes #370 --- rpc/packages.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/rpc/packages.go b/rpc/packages.go index b51bde7ce0..4056494de1 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -25,11 +25,6 @@ import ( "github.com/ethereum/go-ethereum/xeth" ) -const ( - defaultGasPrice = "10000000000000" - defaultGas = "10000" -) - type EthereumApi struct { xeth *xeth.XEth quit chan struct{} @@ -45,17 +40,22 @@ type EthereumApi struct { register map[string][]*NewTxArgs db ethutil.Database + + defaultGasPrice *big.Int + defaultGas *big.Int } func NewEthereumApi(eth *xeth.XEth) *EthereumApi { db, _ := ethdb.NewLDBDatabase("dapps") api := &EthereumApi{ - xeth: eth, - quit: make(chan struct{}), - filterManager: filter.NewFilterManager(eth.Backend().EventMux()), - logs: make(map[int]*logFilter), - messages: make(map[int]*whisperFilter), - db: db, + xeth: eth, + quit: make(chan struct{}), + filterManager: filter.NewFilterManager(eth.Backend().EventMux()), + logs: make(map[int]*logFilter), + messages: make(map[int]*whisperFilter), + db: db, + defaultGasPrice: big.NewInt(10000000000000), + defaultGas: big.NewInt(10000), } go api.filterManager.Start() go api.start() @@ -192,11 +192,11 @@ func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if len(args.Gas) == 0 { - args.Gas = defaultGas + args.Gas = p.defaultGas.String() } if len(args.GasPrice) == 0 { - args.GasPrice = defaultGasPrice + args.GasPrice = p.defaultGasPrice.String() } // TODO if no_private_key then @@ -525,7 +525,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.AllLogs(args, reply) case "eth_gasPrice": - *reply = defaultGasPrice + *reply = "0x" + toHex(p.defaultGasPrice.Bytes()) return nil case "eth_register": args, err := req.ToRegisterArgs() From 3fcdafebc262f42bfa80fcffdeb322c37f6eacf3 Mon Sep 17 00:00:00 2001 From: Fabian Vogelsteller Date: Tue, 24 Feb 2015 16:18:27 +0100 Subject: [PATCH 56/78] topics fix --- rpc/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/util.go b/rpc/util.go index 00a418783a..3e8ca3fef0 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -82,7 +82,7 @@ type RpcServer interface { type Log struct { Address string `json:"address"` - Topic []string `json:"topics"` + Topic []string `json:"topic"` Data string `json:"data"` Number uint64 `json:"number"` } From 2a7ca69a8260b887a309e1c43a74b4e644c391fa Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 24 Feb 2015 16:46:43 +0100 Subject: [PATCH 57/78] Fix duplicate leading 0x --- rpc/packages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/packages.go b/rpc/packages.go index 4056494de1..e48005d899 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -525,7 +525,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.AllLogs(args, reply) case "eth_gasPrice": - *reply = "0x" + toHex(p.defaultGasPrice.Bytes()) + *reply = toHex(p.defaultGasPrice.Bytes()) return nil case "eth_register": args, err := req.ToRegisterArgs() From 1e919a5e977f81b746568e50604b63d1dd393a6b Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 24 Feb 2015 17:32:11 +0100 Subject: [PATCH 58/78] Move amounts to global vars --- rpc/packages.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/rpc/packages.go b/rpc/packages.go index e48005d899..bf75d1ddba 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -25,6 +25,11 @@ import ( "github.com/ethereum/go-ethereum/xeth" ) +var ( + defaultGasPrice = big.NewInt(10000000000000) + defaultGas = big.NewInt(10000) +) + type EthereumApi struct { xeth *xeth.XEth quit chan struct{} @@ -40,22 +45,17 @@ type EthereumApi struct { register map[string][]*NewTxArgs db ethutil.Database - - defaultGasPrice *big.Int - defaultGas *big.Int } func NewEthereumApi(eth *xeth.XEth) *EthereumApi { db, _ := ethdb.NewLDBDatabase("dapps") api := &EthereumApi{ - xeth: eth, - quit: make(chan struct{}), - filterManager: filter.NewFilterManager(eth.Backend().EventMux()), - logs: make(map[int]*logFilter), - messages: make(map[int]*whisperFilter), - db: db, - defaultGasPrice: big.NewInt(10000000000000), - defaultGas: big.NewInt(10000), + xeth: eth, + quit: make(chan struct{}), + filterManager: filter.NewFilterManager(eth.Backend().EventMux()), + logs: make(map[int]*logFilter), + messages: make(map[int]*whisperFilter), + db: db, } go api.filterManager.Start() go api.start() @@ -192,11 +192,11 @@ func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if len(args.Gas) == 0 { - args.Gas = p.defaultGas.String() + args.Gas = defaultGas.String() } if len(args.GasPrice) == 0 { - args.GasPrice = p.defaultGasPrice.String() + args.GasPrice = defaultGasPrice.String() } // TODO if no_private_key then @@ -525,7 +525,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.AllLogs(args, reply) case "eth_gasPrice": - *reply = toHex(p.defaultGasPrice.Bytes()) + *reply = toHex(defaultGasPrice.Bytes()) return nil case "eth_register": args, err := req.ToRegisterArgs() From 923950ccaaa4f9c1c0cebfbdd99fb0f16c47fd37 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Tue, 24 Feb 2015 18:03:10 +0100 Subject: [PATCH 59/78] Fix key store address hex decoding and accounts test Thanks to https://github.com/jaekwon for original fix! --- accounts/account_manager.go | 4 ++++ accounts/accounts_test.go | 14 +++++++++++++- crypto/key_store_plain.go | 7 +++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/accounts/account_manager.go b/accounts/account_manager.go index da0bd89004..f7a7506ba2 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -56,6 +56,10 @@ func NewAccountManager(keyStore crypto.KeyStore2) AccountManager { return *am } +func (am AccountManager) DeleteAccount(address []byte, auth string) error { + return am.keyStore.DeleteKey(address, auth) +} + func (am *AccountManager) Sign(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) { key, err := am.keyStore.GetKey(fromAccount.Address, keyAuth) if err != nil { diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go index 127334404f..4e97de5456 100644 --- a/accounts/accounts_test.go +++ b/accounts/accounts_test.go @@ -9,7 +9,7 @@ import ( ) func TestAccountManager(t *testing.T) { - ks := crypto.NewKeyStorePlain(ethutil.DefaultDataDir()) + ks := crypto.NewKeyStorePlain(ethutil.DefaultDataDir() + "/testaccounts") am := NewAccountManager(ks) pass := "" // not used but required by API a1, err := am.NewAccount(pass) @@ -18,4 +18,16 @@ func TestAccountManager(t *testing.T) { if err != nil { t.Fatal(err) } + + // Cleanup + accounts, err := am.Accounts() + if err != nil { + t.Fatal(err) + } + for _, account := range accounts { + err := am.DeleteAccount(account.Address, pass) + if err != nil { + t.Fatal(err) + } + } } diff --git a/crypto/key_store_plain.go b/crypto/key_store_plain.go index 255ae0ed72..338a4a2c34 100644 --- a/crypto/key_store_plain.go +++ b/crypto/key_store_plain.go @@ -119,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 } From 21becb0febdf11132a40ff69c6145d9babf8458d Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 24 Feb 2015 19:05:03 +0100 Subject: [PATCH 60/78] Cleanup RPC packcage --- rpc/args.go | 66 ++++++--------------- rpc/message.go | 150 ++++++++++++++++++++++-------------------------- rpc/packages.go | 5 +- 3 files changed, 90 insertions(+), 131 deletions(-) diff --git a/rpc/args.go b/rpc/args.go index 347f604109..e839da8bf9 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -19,7 +19,7 @@ func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) { obj.Hash = argstr return } - return NewErrorResponse(ErrorDecodeArgs) + return errDecodeArgs } type NewTxArgs struct { @@ -57,7 +57,7 @@ func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { return } - return NewErrorResponse(ErrorDecodeArgs) + return errDecodeArgs } type PushTxArgs struct { @@ -70,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 } @@ -86,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 } @@ -109,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 } @@ -177,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 } @@ -202,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 } @@ -218,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 } @@ -270,10 +240,10 @@ type DbArgs struct { func (a *DbArgs) requirements() error { if len(a.Database) == 0 { - return NewErrorResponse("DbPutArgs requires an 'Database' value as argument") + return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Database' value as argument") } if len(a.Key) == 0 { - return NewErrorResponse("DbPutArgs requires an 'Key' value as argument") + return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Key' value as argument") } return nil } diff --git a/rpc/message.go b/rpc/message.go index 825ede05b7..18fbec931f 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -25,12 +25,12 @@ 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") + errParseRequest = errors.New("Error: Could not parse request") + errDecodeArgs = errors.New("Error: Could not decode arguments") ) type RpcRequest struct { @@ -58,76 +58,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 +131,228 @@ 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 } - 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 +360,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 +374,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 +388,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 +402,6 @@ func (req *RpcRequest) ToWatchTxArgs() (string, error) { if err != nil { return "", err } - rpclogger.DebugDetailf("%T %v", args, args) + return args, nil } diff --git a/rpc/packages.go b/rpc/packages.go index 0f00441d26..813fef949e 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -9,7 +9,6 @@ For each request type, define the following: package rpc import ( - "fmt" "math/big" "strings" "sync" @@ -410,7 +409,7 @@ func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error { } func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { - // Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC + // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC rpclogger.DebugDetailf("%T %s", req.Params, req.Params) switch req.Method { case "eth_coinbase": @@ -595,7 +594,7 @@ 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) From 43acad81b3fbee608bf19e6ba32ba27b98d9a7ff Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 24 Feb 2015 19:11:01 +0100 Subject: [PATCH 61/78] Rename files --- rpc/{packages.go => api.go} | 0 rpc/{packages_test.go => api_test.go} | 0 rpc/{message.go => messages.go} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename rpc/{packages.go => api.go} (100%) rename rpc/{packages_test.go => api_test.go} (100%) rename rpc/{message.go => messages.go} (100%) diff --git a/rpc/packages.go b/rpc/api.go similarity index 100% rename from rpc/packages.go rename to rpc/api.go diff --git a/rpc/packages_test.go b/rpc/api_test.go similarity index 100% rename from rpc/packages_test.go rename to rpc/api_test.go diff --git a/rpc/message.go b/rpc/messages.go similarity index 100% rename from rpc/message.go rename to rpc/messages.go From c8e9abff53d869f74211e157abcb2827d181e106 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 24 Feb 2015 19:22:08 +0100 Subject: [PATCH 62/78] Remove errParseRequest --- rpc/http/server.go | 2 +- rpc/messages.go | 1 - rpc/ws/server.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rpc/http/server.go b/rpc/http/server.go index dd6ba68e32..fa66eed487 100644 --- a/rpc/http/server.go +++ b/rpc/http/server.go @@ -92,7 +92,7 @@ func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler { reqParsed, reqerr := JSON.ParseRequestBody(req) if reqerr != nil { - jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest} + jsonerr := &rpc.RpcErrorObject{-32700, "Error: Could not parse request"} JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr}) return } diff --git a/rpc/messages.go b/rpc/messages.go index 18fbec931f..044f07545d 100644 --- a/rpc/messages.go +++ b/rpc/messages.go @@ -29,7 +29,6 @@ var ( errArguments = errors.New("Error: Insufficient arguments") errNotImplemented = errors.New("Error: Method not implemented") errUnknown = errors.New("Error: Unknown error") - errParseRequest = errors.New("Error: Could not parse request") errDecodeArgs = errors.New("Error: Could not decode arguments") ) diff --git a/rpc/ws/server.go b/rpc/ws/server.go index b8cc2fa6b2..2c2988f5d5 100644 --- a/rpc/ws/server.go +++ b/rpc/ws/server.go @@ -99,7 +99,7 @@ func sockHandler(api *rpc.EthereumApi) websocket.Handler { // reqParsed, reqerr := JSON.ParseRequestBody(conn.Request()) if err := websocket.JSON.Receive(conn, &reqParsed); err != nil { - jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest} + jsonerr := &rpc.RpcErrorObject{-32700, "Error: Could not parse request"} JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr}) continue } From 2e3a6e2559d02ba90957eaf333e571dec935e00a Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 24 Feb 2015 19:54:18 +0100 Subject: [PATCH 63/78] Consolidate related items --- rpc/api.go | 73 +++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/rpc/api.go b/rpc/api.go index 813fef949e..21c85bbcc1 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -25,8 +25,9 @@ import ( ) var ( - defaultGasPrice = big.NewInt(10000000000000) - defaultGas = big.NewInt(10000) + defaultGasPrice = big.NewInt(10000000000000) + defaultGas = big.NewInt(10000) + filterTickerTime = 15 * time.Second ) type EthereumApi struct { @@ -62,6 +63,39 @@ func NewEthereumApi(eth *xeth.XEth) *EthereumApi { return api } +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 { + 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() @@ -600,38 +634,3 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error rpclogger.DebugDetailf("Reply: %T %s", reply, reply) return nil } - -var filterTickerTime = 15 * time.Second - -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 { - 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) -} From 9e0ab22dd01d677a853f1af2c865f8654081ca26 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Wed, 25 Feb 2015 09:57:49 +0100 Subject: [PATCH 64/78] Stub defaultBlock methods --- rpc/api.go | 21 +++++++++++++++++++++ rpc/messages.go | 13 +++++++++++++ 2 files changed, 34 insertions(+) diff --git a/rpc/api.go b/rpc/api.go index 21c85bbcc1..908d37a80b 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -45,6 +45,8 @@ type EthereumApi struct { register map[string][]*NewTxArgs db ethutil.Database + + defaultBlockAge int } func NewEthereumApi(eth *xeth.XEth) *EthereumApi { @@ -318,6 +320,17 @@ func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error { return nil } +func (p *EthereumApi) GetDefaultBlockAge(reply *interface{}) error { + *reply = p.defaultBlockAge + return nil +} + +func (p *EthereumApi) SetDefaultBlockAge(defaultBlockAge int, reply *interface{}) error { + p.defaultBlockAge = defaultBlockAge + *reply = true + return nil +} + func (p *EthereumApi) BlockNumber(reply *interface{}) error { *reply = p.xeth.Backend().ChainManager().CurrentBlock().Number() return nil @@ -458,6 +471,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(args, reply) case "eth_peerCount": return p.GetPeerCount(reply) case "eth_number": diff --git a/rpc/messages.go b/rpc/messages.go index 044f07545d..b37d8229d6 100644 --- a/rpc/messages.go +++ b/rpc/messages.go @@ -210,6 +210,19 @@ func (req *RpcRequest) ToBoolArgs() (bool, error) { 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 + } + + return args, nil +} + func (req *RpcRequest) ToCompileArgs() (string, error) { if len(req.Params) < 1 { return "", errArguments From ce2b2422d6efe9d8c4744a83bab8d80d9e94128d Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Wed, 25 Feb 2015 11:40:52 +0100 Subject: [PATCH 65/78] Update Go and Qt versions --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5499cf2571..c4e39b05ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: go go: - - 1.4.1 + - 1.4.2 before_install: - - sudo add-apt-repository ppa:beineri/opt-qt54 -y + - sudo add-apt-repository ppa:beineri/opt-qt541 -y - sudo apt-get update -qq - sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine install: From b296b36d2b2aaa2f81d26b3c133ace2714c58a7d Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Wed, 25 Feb 2015 17:29:23 +0100 Subject: [PATCH 66/78] Add automatic locking / unlocking of accounts * Change account signing API to two sign functions; Sign without passphrase - works if account is unlocked Sign with passphrase - always works and unlocks the account * Account stays unlocked for X ms and is then automatically locked --- accounts/account_manager.go | 48 ++++++++++++++++++++++++++------- accounts/accounts_test.go | 53 +++++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/accounts/account_manager.go b/accounts/account_manager.go index f7a7506ba2..4d63bd0f28 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -34,24 +34,33 @@ package accounts import ( crand "crypto/rand" + "errors" "github.com/ethereum/go-ethereum/crypto" + "sync" + "time" ) +var ErrLocked = errors.New("account is locked; please request passphrase") + // TODO: better name for this struct? type Account struct { Address []byte } type AccountManager struct { - keyStore crypto.KeyStore2 + keyStore crypto.KeyStore2 + unlockedKeys map[string]crypto.Key + unlockedMilliSeconds int + mutex sync.Mutex } -// 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 int) AccountManager { + keysMap := make(map[string]crypto.Key) am := &AccountManager{ - keyStore: keyStore, + keyStore: keyStore, + unlockedKeys: keysMap, + unlockedMilliSeconds: unlockMilliSeconds, + mutex: sync.Mutex{}, // for accessing unlockedKeys map } return *am } @@ -60,11 +69,26 @@ func (am AccountManager) DeleteAccount(address []byte, auth string) error { return am.keyStore.DeleteKey(address, auth) } -func (am *AccountManager) Sign(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) { +func (am *AccountManager) Sign(fromAccount *Account, toSign []byte) (signature []byte, err error) { + am.mutex.Lock() + unlockedKey := am.unlockedKeys[string(fromAccount.Address)] + am.mutex.Unlock() + 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.Lock() + am.unlockedKeys[string(fromAccount.Address)] = *key + am.mutex.Unlock() + go unlockLater(am, fromAccount.Address) signature, err = crypto.Sign(toSign, key.PrivateKey) return signature, err } @@ -80,8 +104,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 { @@ -97,3 +119,11 @@ func (am *AccountManager) Accounts() ([]Account, error) { } return accounts, err } + +func unlockLater(am *AccountManager, addr []byte) { + time.Sleep(time.Millisecond * time.Duration(am.unlockedMilliSeconds)) + am.mutex.Lock() + // TODO: how do we know the key is actually gone from memory? + delete(am.unlockedKeys, string(addr)) + am.mutex.Unlock() +} diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go index 4e97de5456..8f036fd1f1 100644 --- a/accounts/accounts_test.go +++ b/accounts/accounts_test.go @@ -6,19 +6,68 @@ 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(ethutil.DefaultDataDir() + "/testaccounts") - am := NewAccountManager(ks) + 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 * time.Duration(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 { From d1311c53eee916ae8472a3b7eaf40b5e94f7675f Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Wed, 25 Feb 2015 18:40:59 +0100 Subject: [PATCH 67/78] Address pull request comments * Use RWMutex instead of Mutex * Use time.Duration instead of int for unlock time * Use time.After with select instead of time.Sleep --- accounts/account_manager.go | 34 ++++++++++++++++++---------------- accounts/accounts_test.go | 2 +- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 4d63bd0f28..38dd6f736e 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -48,19 +48,19 @@ type Account struct { } type AccountManager struct { - keyStore crypto.KeyStore2 - unlockedKeys map[string]crypto.Key - unlockedMilliSeconds int - mutex sync.Mutex + keyStore crypto.KeyStore2 + unlockedKeys map[string]crypto.Key + unlockMilliseconds time.Duration + mutex sync.RWMutex } -func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliSeconds int) AccountManager { +func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Duration) AccountManager { keysMap := make(map[string]crypto.Key) am := &AccountManager{ - keyStore: keyStore, - unlockedKeys: keysMap, - unlockedMilliSeconds: unlockMilliSeconds, - mutex: sync.Mutex{}, // for accessing unlockedKeys map + keyStore: keyStore, + unlockedKeys: keysMap, + unlockMilliseconds: unlockMilliseconds, + mutex: sync.RWMutex{}, // for accessing unlockedKeys map } return *am } @@ -70,9 +70,9 @@ func (am AccountManager) DeleteAccount(address []byte, auth string) error { } func (am *AccountManager) Sign(fromAccount *Account, toSign []byte) (signature []byte, err error) { - am.mutex.Lock() + am.mutex.RLock() unlockedKey := am.unlockedKeys[string(fromAccount.Address)] - am.mutex.Unlock() + am.mutex.RUnlock() if unlockedKey.Address == nil { return nil, ErrLocked } @@ -85,9 +85,9 @@ func (am *AccountManager) SignLocked(fromAccount *Account, keyAuth string, toSig if err != nil { return nil, err } - am.mutex.Lock() + am.mutex.RLock() am.unlockedKeys[string(fromAccount.Address)] = *key - am.mutex.Unlock() + am.mutex.RUnlock() go unlockLater(am, fromAccount.Address) signature, err = crypto.Sign(toSign, key.PrivateKey) return signature, err @@ -121,9 +121,11 @@ func (am *AccountManager) Accounts() ([]Account, error) { } func unlockLater(am *AccountManager, addr []byte) { - time.Sleep(time.Millisecond * time.Duration(am.unlockedMilliSeconds)) - am.mutex.Lock() + 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.Unlock() + am.mutex.RUnlock() } diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go index 8f036fd1f1..44d1d72f17 100644 --- a/accounts/accounts_test.go +++ b/accounts/accounts_test.go @@ -21,7 +21,7 @@ func TestAccountManager(t *testing.T) { } // Cleanup - time.Sleep(time.Millisecond * time.Duration(150)) // wait for locking + time.Sleep(time.Millisecond * 150) // wait for locking accounts, err := am.Accounts() if err != nil { From 23f265809170fae044be12851f5591f55495003a Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Wed, 25 Feb 2015 19:30:57 +0100 Subject: [PATCH 68/78] Remove unneeded initialisation of mutex --- accounts/account_manager.go | 1 - 1 file changed, 1 deletion(-) diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 38dd6f736e..90fed13432 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -60,7 +60,6 @@ func NewAccountManager(keyStore crypto.KeyStore2, unlockMilliseconds time.Durati keyStore: keyStore, unlockedKeys: keysMap, unlockMilliseconds: unlockMilliseconds, - mutex: sync.RWMutex{}, // for accessing unlockedKeys map } return *am } From 260ab739694b554c3cdec8531b98e0334753fbe1 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Wed, 25 Feb 2015 20:00:32 +0100 Subject: [PATCH 69/78] Validate block header gas limit * Add block header gas limit validation in ValidateBlock function, see eq 39 and 45 in yellow paper. Before it was calculated _for_ the block instead of validated. * Use the block header gas limit when setting the gas pool instead of calculating the value for the block. --- core/block_processor.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/block_processor.go b/core/block_processor.go index fd591a29d8..f66d158b2f 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -62,7 +62,7 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) { coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase) - coinbase.SetGasPool(CalcGasLimit(parent, block)) + coinbase.SetGasPool(block.Header().GasLimit) // Process the transactions on to parent state receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess) @@ -247,6 +247,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error { return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd) } + expl := CalcGasLimit(parent, block) + if expl.Cmp(block.Header().GasLimit) != 0 { + return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl) + } + if block.Time() < parent.Time() { return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time) } From 8eeab7ea3fb7a01a610e46940141eecf7435873a Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 26 Feb 2015 02:24:20 +0100 Subject: [PATCH 70/78] Update osext import path --- cmd/mist/flags.go | 2 +- cmd/utils/cmd.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/mist/flags.go b/cmd/mist/flags.go index d5ed60a211..c4edb8dae8 100644 --- a/cmd/mist/flags.go +++ b/cmd/mist/flags.go @@ -30,12 +30,12 @@ import ( "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" + "github.com/kardianos/osext" ) var ( diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index bc8fafafb2..d78b6a94da 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -30,7 +30,6 @@ import ( "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" @@ -42,6 +41,7 @@ import ( rpcws "github.com/ethereum/go-ethereum/rpc/ws" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/xeth" + "github.com/kardianos/osext" ) var clilogger = logger.NewLogger("CLI") From d5aed82b11589bb3f8b0df4544081fe898b8c724 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 26 Feb 2015 02:32:27 +0100 Subject: [PATCH 71/78] DRY DefaultAssetPath() --- cmd/mist/flags.go | 29 +---------------------------- cmd/utils/cmd.go | 26 -------------------------- ethutil/common.go | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 54 deletions(-) diff --git a/cmd/mist/flags.go b/cmd/mist/flags.go index c4edb8dae8..8dab59d808 100644 --- a/cmd/mist/flags.go +++ b/cmd/mist/flags.go @@ -68,33 +68,6 @@ 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 -} - var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini") func Init() { @@ -122,7 +95,7 @@ func Init() { flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") - flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory") + flag.StringVar(&AssetPath, "asset_path", ethutil.DefaultAssetPath(), "absolute path to GUI assets directory") // Network stuff var ( diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index d78b6a94da..a65476e69a 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -41,7 +41,6 @@ import ( rpcws "github.com/ethereum/go-ethereum/rpc/ws" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/xeth" - "github.com/kardianos/osext" ) var clilogger = logger.NewLogger("CLI") @@ -132,31 +131,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 diff --git a/ethutil/common.go b/ethutil/common.go index efc519732c..d439dcedc0 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -2,6 +2,7 @@ package ethutil import ( "fmt" + "github.com/kardianos/osext" "math/big" "os/user" "path" @@ -9,6 +10,31 @@ import ( "time" ) +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" { From 739b7cc2ac7de9c6c24547be00de81338089d724 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 26 Feb 2015 02:36:06 +0100 Subject: [PATCH 72/78] Cleanup imports --- cmd/mist/flags.go | 2 -- cmd/utils/cmd.go | 3 --- ethutil/common.go | 5 ++++- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cmd/mist/flags.go b/cmd/mist/flags.go index 8dab59d808..0010df8265 100644 --- a/cmd/mist/flags.go +++ b/cmd/mist/flags.go @@ -27,7 +27,6 @@ import ( "log" "os" "path" - "path/filepath" "runtime" "github.com/ethereum/go-ethereum/crypto" @@ -35,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/vm" - "github.com/kardianos/osext" ) var ( diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index a65476e69a..a36c10e3bf 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -25,10 +25,7 @@ import ( "fmt" "os" "os/signal" - "path" - "path/filepath" "regexp" - "runtime" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" diff --git a/ethutil/common.go b/ethutil/common.go index d439dcedc0..c4e7415dc1 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -2,12 +2,15 @@ package ethutil import ( "fmt" - "github.com/kardianos/osext" "math/big" + "os" "os/user" "path" + "path/filepath" "runtime" "time" + + "github.com/kardianos/osext" ) func DefaultAssetPath() string { From 57cea0c623ed808ad134bd62610afb6b842f5d0d Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 26 Feb 2015 02:48:55 +0100 Subject: [PATCH 73/78] Update godeps --- Godeps/Godeps.json | 11 ++++---- .../src/bitbucket.org/kardianos/osext/LICENSE | 20 -------------- .../src/github.com/kardianos/osext/LICENSE | 27 +++++++++++++++++++ .../src/github.com/kardianos/osext/README.md | 14 ++++++++++ .../kardianos/osext/osext.go | 5 ---- .../kardianos/osext/osext_plan9.go | 18 ++++++------- .../kardianos/osext/osext_procfs.go | 7 +++-- .../kardianos/osext/osext_sysctl.go | 0 .../kardianos/osext/osext_test.go | 0 .../kardianos/osext/osext_windows.go | 0 10 files changed, 60 insertions(+), 42 deletions(-) delete mode 100644 Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/LICENSE create mode 100644 Godeps/_workspace/src/github.com/kardianos/osext/README.md rename Godeps/_workspace/src/{bitbucket.org => github.com}/kardianos/osext/osext.go (87%) rename Godeps/_workspace/src/{bitbucket.org => github.com}/kardianos/osext/osext_plan9.go (51%) rename Godeps/_workspace/src/{bitbucket.org => github.com}/kardianos/osext/osext_procfs.go (74%) rename Godeps/_workspace/src/{bitbucket.org => github.com}/kardianos/osext/osext_sysctl.go (100%) rename Godeps/_workspace/src/{bitbucket.org => github.com}/kardianos/osext/osext_test.go (100%) rename Godeps/_workspace/src/{bitbucket.org => github.com}/kardianos/osext/osext_windows.go (100%) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 9b73065309..b66ea932fe 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,15 +1,10 @@ { "ImportPath": "github.com/ethereum/go-ethereum", - "GoVersion": "go1.4.1", + "GoVersion": "go1.4.2", "Packages": [ "./..." ], "Deps": [ - { - "ImportPath": "bitbucket.org/kardianos/osext", - "Comment": "null-13", - "Rev": "5d3ddcf53a508cc2f7404eaebf546ef2cb5cdb6e" - }, { "ImportPath": "code.google.com/p/go-uuid/uuid", "Comment": "null-12", @@ -37,6 +32,10 @@ "ImportPath": "github.com/jackpal/go-nat-pmp", "Rev": "a45aa3d54aef73b504e15eb71bea0e5565b5e6e1" }, + { + "ImportPath": "github.com/kardianos/osext", + "Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a" + }, { "ImportPath": "github.com/obscuren/otto", "Rev": "cf13cc4228c5e5ce0fe27a7aea90bc10091c4f19" diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE b/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE deleted file mode 100644 index 18527a28fb..0000000000 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2012 Daniel Theophanes - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/LICENSE b/Godeps/_workspace/src/github.com/kardianos/osext/LICENSE new file mode 100644 index 0000000000..7448756763 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/kardianos/osext/README.md b/Godeps/_workspace/src/github.com/kardianos/osext/README.md new file mode 100644 index 0000000000..820e1ecb54 --- /dev/null +++ b/Godeps/_workspace/src/github.com/kardianos/osext/README.md @@ -0,0 +1,14 @@ +### Extensions to the "os" package. + +## Find the current Executable and ExecutableFolder. + +There is sometimes utility in finding the current executable file +that is running. This can be used for upgrading the current executable +or finding resources located relative to the executable file. + +Multi-platform and supports: + * Linux + * OS X + * Windows + * Plan 9 + * BSDs. diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext.go similarity index 87% rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go rename to Godeps/_workspace/src/github.com/kardianos/osext/osext.go index 37efbb2210..4ed4b9aa33 100644 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext.go @@ -25,8 +25,3 @@ func ExecutableFolder() (string, error) { folder, _ := filepath.Split(p) return folder, nil } - -// Depricated. Same as Executable(). -func GetExePath() (exePath string, err error) { - return Executable() -} diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go similarity index 51% rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go index 4468a73a7f..655750c542 100644 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go @@ -5,16 +5,16 @@ package osext import ( - "syscall" - "os" - "strconv" + "os" + "strconv" + "syscall" ) func executable() (string, error) { - f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") - if err != nil { - return "", err - } - defer f.Close() - return syscall.Fd2path(int(f.Fd())) + f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") + if err != nil { + return "", err + } + defer f.Close() + return syscall.Fd2path(int(f.Fd())) } diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go similarity index 74% rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go index 546fec9155..a50021ad53 100644 --- a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go +++ b/Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux netbsd openbsd +// +build linux netbsd openbsd solaris dragonfly package osext import ( "errors" + "fmt" "os" "runtime" ) @@ -18,8 +19,10 @@ func executable() (string, error) { return os.Readlink("/proc/self/exe") case "netbsd": return os.Readlink("/proc/curproc/exe") - case "openbsd": + case "openbsd", "dragonfly": return os.Readlink("/proc/curproc/file") + case "solaris": + return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid())) } return "", errors.New("ExecPath not implemented for " + runtime.GOOS) } diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go similarity index 100% rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go similarity index 100% rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go diff --git a/Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go b/Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go similarity index 100% rename from Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go rename to Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go From 5ab0eaa06d2f5879b9b22778988410bd0c73dcc0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 11:14:54 +0100 Subject: [PATCH 74/78] wip --- accounts/account_manager.go | 1 + rpc/api.go | 146 ++++++++++++++++++++++++++++-------- xeth/world.go | 32 -------- xeth/xeth.go | 22 +++++- 4 files changed, 132 insertions(+), 69 deletions(-) delete mode 100644 xeth/world.go diff --git a/accounts/account_manager.go b/accounts/account_manager.go index f7a7506ba2..f1ad450e62 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -34,6 +34,7 @@ package accounts import ( crand "crypto/rand" + "github.com/ethereum/go-ethereum/crypto" ) diff --git a/rpc/api.go b/rpc/api.go index 21c85bbcc1..f337324d0f 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -9,6 +9,7 @@ For each request type, define the following: package rpc import ( + "fmt" "math/big" "strings" "sync" @@ -19,8 +20,10 @@ 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" ) @@ -31,7 +34,10 @@ var ( ) type EthereumApi struct { - xeth *xeth.XEth + eth *xeth.XEth + xethMu sync.RWMutex + mux *event.TypeMux + quit chan struct{} filterManager *filter.FilterManager @@ -50,7 +56,8 @@ type EthereumApi struct { 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), @@ -65,9 +72,25 @@ func NewEthereumApi(eth *xeth.XEth) *EthereumApi { 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: + // fixme + const something = 1337 + if something < 0 { + chain := self.xeth().Backend().ChainManager() + block := chain.GetBlockByNumber(chain.CurrentBlock().Number().Uint64() - something) + if block != nil { + statedb := state.New(block.Root(), self.db) + self.useState(statedb) + } + } + } case <-timer.C: self.logMut.Lock() self.messagesMut.Lock() @@ -80,7 +103,7 @@ done: for id, filter := range self.messages { if time.Since(filter.timeout) > 20*time.Second { - self.xeth.Whisper().Unwatch(id) + self.xeth().Whisper().Unwatch(id) delete(self.messages, id) } } @@ -128,7 +151,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() @@ -153,7 +176,7 @@ 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() @@ -198,7 +221,7 @@ func (self *EthereumApi) Logs(id int, reply *interface{}) error { } func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error { - filter := core.NewFilter(self.xeth.Backend()) + filter := core.NewFilter(self.xeth().Backend()) filter.SetOptions(toFilterOptions(args)) *reply = toLogs(filter.Find()) @@ -209,13 +232,28 @@ func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error 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) + *reply = p.xeth().BlockByHash(args.Hash) } else { - *reply = p.xeth.BlockByNumber(args.BlockNumber) + *reply = p.xeth().BlockByNumber(args.BlockNumber) } return nil } +/* +func unlockAccount(server, account *Account) bool { + pwd, status := server.PasswordDialog() + switch status { + case Ok: + if !account.Unlock([]byte(pwd)) { + return unlockAccount(account) + } + return true + default: + return false + } +} +*/ + func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if len(args.Gas) == 0 { args.Gas = defaultGas.String() @@ -226,18 +264,35 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { } // 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 } @@ -251,7 +306,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 } @@ -262,7 +317,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 @@ -284,42 +339,42 @@ 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) BlockNumber(reply *interface{}) error { - *reply = p.xeth.Backend().ChainManager().CurrentBlock().Number() + *reply = p.xeth().Backend().ChainManager().CurrentBlock().Number() return nil } @@ -328,7 +383,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 } @@ -337,7 +392,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 } @@ -347,7 +402,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 } @@ -394,7 +449,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 } @@ -405,7 +460,7 @@ func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) e defer p.messagesMut.Unlock() 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 @@ -423,7 +478,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 } @@ -433,12 +488,12 @@ 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 } @@ -634,3 +689,28 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error rpclogger.DebugDetailf("Reply: %T %s", reply, reply) return nil } + +func (self *EthereumApi) xeth() *xeth.XEth { + self.xethMu.RLock() + defer self.xethMu.RUnlock() + + return self.eth +} + +func (self *EthereumApi) useState(statedb *state.StateDB) { + self.xethMu.Lock() + defer self.xethMu.Unlock() + + self.eth = self.xeth().UseState(statedb) +} + +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) +} diff --git a/xeth/world.go b/xeth/world.go deleted file mode 100644 index 9cbdd9461e..0000000000 --- a/xeth/world.go +++ /dev/null @@ -1,32 +0,0 @@ -package xeth - -import "github.com/ethereum/go-ethereum/state" - -type State struct { - xeth *XEth -} - -func NewState(xeth *XEth) *State { - return &State{xeth} -} - -func (self *State) State() *state.StateDB { - return self.xeth.chainManager.TransState() -} - -func (self *State) Get(addr string) *Object { - return &Object{self.State().GetStateObject(fromHex(addr))} -} - -func (self *State) SafeGet(addr string) *Object { - return &Object{self.safeGet(addr)} -} - -func (self *State) safeGet(addr string) *state.StateObject { - object := self.State().GetStateObject(fromHex(addr)) - if object == nil { - object = state.NewStateObject(fromHex(addr), self.xeth.eth.Db()) - } - - return object -} diff --git a/xeth/xeth.go b/xeth/xeth.go index 2985ce982e..d4c188fec2 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/whisper" ) @@ -54,13 +55,26 @@ func New(eth Backend) *XEth { whisper: NewWhisper(eth.Whisper()), miner: eth.Miner(), } - xeth.state = NewState(xeth) + xeth.state = NewState(xeth, xeth.chainManager.TransState()) return xeth } -func (self *XEth) Backend() Backend { return self.eth } -func (self *XEth) State() *State { return self.state } +func (self *XEth) Backend() Backend { return self.eth } +func (self *XEth) UseState(statedb *state.StateDB) *XEth { + xeth := &XEth{ + eth: self.eth, + blockProcessor: self.blockProcessor, + chainManager: self.chainManager, + whisper: self.whisper, + miner: self.miner, + } + + xeth.state = NewState(xeth, statedb) + return xeth +} +func (self *XEth) State() *State { return self.state } + func (self *XEth) Whisper() *Whisper { return self.whisper } func (self *XEth) Miner() *miner.Miner { return self.miner } @@ -229,7 +243,7 @@ func (self *XEth) Call(toStr, valueStr, gasStr, gasPriceStr, dataStr string) (st } var ( - statedb = self.chainManager.TransState() + statedb = self.State().State() //self.chainManager.TransState() key = self.eth.KeyManager().KeyPair() from = statedb.GetOrNewStateObject(key.Address()) block = self.chainManager.CurrentBlock() From a1c830cd3c53bce7748d97e3f99fe6a90d526adb Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 12:06:10 +0100 Subject: [PATCH 75/78] Defautl block --- cmd/mist/assets/examples/info.html | 7 +- .../assets/ext/ethereum.js/dist/ethereum.js | 734 +++++++++++------- rpc/api.go | 63 +- 3 files changed, 488 insertions(+), 316 deletions(-) diff --git a/cmd/mist/assets/examples/info.html b/cmd/mist/assets/examples/info.html index 2a405c280a..3b958a4945 100644 --- a/cmd/mist/assets/examples/info.html +++ b/cmd/mist/assets/examples/info.html @@ -62,6 +62,8 @@ web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545')); + eth.defaultBlock = -2 + document.querySelector("#number").innerHTML = eth.number; document.querySelector("#coinbase").innerHTML = eth.coinbase document.querySelector("#peer_count").innerHTML = eth.peerCount; @@ -72,8 +74,9 @@ document.querySelector("#mining").innerHTML = eth.mining; document.querySelector("#listening").innerHTML = eth.listening; eth.watch('chain').changed(function() { - document.querySelector("#number").innerHTML = eth.number; - }); + document.querySelector("#number").innerHTML = eth.number; + }); + diff --git a/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js b/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js index 83b598b3f1..522b77ebfd 100644 --- a/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js +++ b/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js @@ -53,7 +53,6 @@ var inputTypes = types.inputTypes(); /// @returns bytes representation of input params var formatInput = function (inputs, params) { var bytes = ""; - var padding = c.ETH_PADDING * 2; /// first we iterate in search for dynamic inputs.forEach(function (input, index) { @@ -110,6 +109,7 @@ var formatOutput = function (outs, output) { output = output.slice(dynamicPartLength); outs.forEach(function (out, i) { + /*jshint maxcomplexity:6 */ var typeMatch = false; for (var j = 0; j < outputTypes.length && !typeMatch; j++) { typeMatch = outputTypes[j].type(outs[i].type); @@ -210,7 +210,7 @@ module.exports = { }; -},{"./const":2,"./formatters":6,"./types":11,"./utils":12,"./web3":13}],2:[function(require,module,exports){ +},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -264,7 +264,8 @@ module.exports = { ETH_PADDING: 32, ETH_SIGNATURE_LENGTH: 4, ETH_UNITS: ETH_UNITS, - ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } + ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, + ETH_POLLING_TIMEOUT: 1000 }; @@ -340,6 +341,7 @@ var addFunctionsToContract = function (contract, desc, address) { var typeName = utils.extractTypeName(method.name); var impl = function () { + /*jshint maxcomplexity:7 */ var params = Array.prototype.slice.call(arguments); var signature = abi.signatureFromAscii(method.name); var parsed = inputParser[displayName][typeName].apply(null, params); @@ -416,11 +418,11 @@ var addEventsToContract = function (contract, desc, address) { var signature = abi.eventSignatureFromAscii(e.name); var event = eventImpl.inputParser(address, signature, e); var o = event.apply(null, params); - o._onWatchEventResult = function (data) { + var outputFormatter = function (data) { var parser = eventImpl.outputParser(e); return parser(data); }; - return web3.eth.watch(o); + return web3.eth.watch(o, undefined, undefined, outputFormatter); }; // this property should be used by eth.filter to check if object is an event @@ -487,7 +489,131 @@ var contract = function (address, desc) { module.exports = contract; -},{"./abi":1,"./event":4,"./utils":12,"./web3":13}],4:[function(require,module,exports){ +},{"./abi":1,"./event":6,"./utils":15,"./web3":17}],4:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file db.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.db api methods +var methods = function () { + return [ + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } + ]; +}; + +module.exports = { + methods: methods +}; + +},{}],5:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file eth.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.eth api methods +var methods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + }; + + var transactionCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber'; + }; + + var uncleCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber'; + }; + + return [ + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compilers', call: 'eth_compilers' }, + { name: 'flush', call: 'eth_flush' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' }, + { name: 'logs', call: 'eth_logs' }, + { name: 'transactionCount', call: transactionCountCall }, + { name: 'uncleCount', call: uncleCountCall } + ]; +}; + +/// @returns an array of objects describing web3.eth api properties +var properties = function () { + return [ + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} + ]; +}; + +module.exports = { + methods: methods, + properties: properties +}; + + +},{}],6:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -571,9 +697,9 @@ var getArgumentsObject = function (inputs, indexed, notIndexed) { return inputs.reduce(function (acc, current) { var value; if (current.indexed) - value = indexed.splice(0, 1)[0]; + value = indexedCopy.splice(0, 1)[0]; else - value = notIndexed.splice(0, 1)[0]; + value = notIndexedCopy.splice(0, 1)[0]; acc[current.name] = value; return acc; @@ -589,6 +715,7 @@ var outputParser = function (event) { args: {} }; + output.topics = output.topic; // fallback for go-ethereum if (!output.topic) { return result; } @@ -624,7 +751,7 @@ module.exports = { }; -},{"./abi":1,"./utils":12}],5:[function(require,module,exports){ +},{"./abi":1,"./utils":15}],7:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -650,84 +777,96 @@ module.exports = { * @date 2014 */ -var web3 = require('./web3'); // jshint ignore:line - -/// should be used when we want to watch something -/// it's using inner polling mechanism and is notified about changes -/// TODO: change 'options' name cause it may be not the best matching one, since we have events -var Filter = function(options, impl) { - - if (typeof options !== "string") { - - // topics property is deprecated, warn about it! - if (options.topics) { - console.warn('"topics" is deprecated, use "topic" instead'); - } - - this._onWatchResult = options._onWatchEventResult; - - // evaluate lazy properties - options = { - to: options.to, - topic: options.topic, - earliest: options.earliest, - latest: options.latest, - max: options.max, - skip: options.skip, - address: options.address - }; - +/// 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'; +}; + +/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones +/// @param should be string or object +/// @returns options string or object +var getOptions = function (options) { + if (typeof options === 'string') { + return options; + } + + options = options || {}; + + if (options.topics) { + console.warn('"topics" is deprecated, is "topic" instead'); } - - 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)); + // evaluate lazy properties + return { + to: options.to, + topic: options.topic, + earliest: options.earliest, + latest: options.latest, + max: options.max, + skip: options.skip, + address: options.address + }; }; -/// alias for changed* -Filter.prototype.arrived = function(callback) { - this.changed(callback); -}; -Filter.prototype.happened = function(callback) { - this.changed(callback); -}; +/// 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; + } -/// gets called when there is new eth/shh message -Filter.prototype.changed = function(callback) { - this.callbacks.push(callback); -}; + 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); + }); + }); + }; -/// 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); - } - } -}; + implementation.startPolling(filterId, onMessages, implementation.uninstallFilter); -/// should be called to uninstall current filter -Filter.prototype.uninstall = function() { - this.impl.uninstallFilter(this.id); - web3.provider.stopPolling(this.id); -}; + var changed = function (callback) { + callbacks.push(callback); + }; -/// should be called to manually trigger getting latest messages from the client -Filter.prototype.messages = function() { - return this.impl.getMessages(this.id); -}; + var messages = function () { + return implementation.getMessages(filterId); + }; + + var uninstall = function () { + implementation.stopPolling(filterId); + implementation.uninstallFilter(filterId); + callbacks = []; + }; -/// alias for messages -Filter.prototype.logs = function () { - return this.messages(); + return { + changed: changed, + arrived: changed, + happened: changed, + messages: messages, + logs: messages, + uninstall: uninstall + }; }; -module.exports = Filter; +module.exports = filter; + -},{"./web3":13}],6:[function(require,module,exports){ +},{}],8:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -770,6 +909,7 @@ var padLeft = function (string, chars, sign) { /// If the value is floating point, round it down /// @returns right-aligned byte representation of int var formatInputInt = function (value) { + /*jshint maxcomplexity:7 */ var padding = c.ETH_PADDING * 2; if (value instanceof BigNumber || typeof value === 'number') { if (typeof value === 'number') @@ -883,7 +1023,7 @@ module.exports = { }; -},{"./const":2,"./utils":12}],7:[function(require,module,exports){ +},{"./const":2,"./utils":15}],9:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -918,20 +1058,22 @@ var HttpSyncProvider = function (host) { HttpSyncProvider.prototype.send = function (payload) { //var data = formatJsonRpcObject(payload); - + var request = new XMLHttpRequest(); request.open('POST', this.host, false); request.send(JSON.stringify(payload)); - - // check request.status + var result = request.responseText; + // check request.status + if(request.status !== 200) + return; return JSON.parse(result); }; module.exports = HttpSyncProvider; -},{}],8:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -998,7 +1140,7 @@ module.exports = { -},{}],9:[function(require,module,exports){ +},{}],11:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1015,7 +1157,42 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file providermanager.js +/** @file qtsync.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +var QtSyncProvider = function () { +}; + +QtSyncProvider.prototype.send = function (payload) { + var result = navigator.qt.callMethod(JSON.stringify(payload)); + return JSON.parse(result); +}; + +module.exports = QtSyncProvider; + + +},{}],12:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file requestmanager.js * @authors: * Jeffrey Wilcke * Marek Kotewicz @@ -1024,85 +1201,95 @@ module.exports = { * @date 2014 */ -var web3 = require('./web3'); var jsonrpc = require('./jsonrpc'); - +var c = require('./const'); /** - * 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 + * Default poll timeout is 1 second */ -var ProviderManager = function() { - this.polls = []; - this.provider = undefined; +var requestManager = function() { + var polls = []; + var timeout = null; + var provider; - 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; - } + var send = function (data) { + var payload = jsonrpc.toPayload(data.method, data.params); + + if (!provider) { + console.error('provider is not set'); + return null; + } - data.callback(result); - }); + var result = provider.send(payload); - setTimeout(poll, 1000); + if (!jsonrpc.isValidResponse(result)) { + console.log(result); + return null; + } + + return result.result; }; - 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 setProvider = function (p) { + provider = p; + }; - var result = this.provider.send(payload); + /*jshint maxparams:4 */ + var startPolling = function (data, pollId, callback, uninstall) { + polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); + }; + /*jshint maxparams:3 */ - if (!jsonrpc.isValidResponse(result)) { - console.log(result); - return null; - } + var stopPolling = function (pollId) { + for (var i = polls.length; i--;) { + var poll = polls[i]; + if (poll.id === pollId) { + polls.splice(i, 1); + } + } + }; - return result.result; -}; + var reset = function () { + polls.forEach(function (poll) { + poll.uninstall(poll.id); + }); + polls = []; -/// setups provider, which will be used for sending messages -ProviderManager.prototype.set = function(provider) { - this.provider = provider; -}; + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + poll(); + }; -/// 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}); -}; + 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(); -/// 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); - } - } + return { + send: send, + setProvider: setProvider, + startPolling: startPolling, + stopPolling: stopPolling, + reset: reset + }; }; -module.exports = ProviderManager; +module.exports = requestManager; -},{"./jsonrpc":8,"./web3":13}],10:[function(require,module,exports){ +},{"./const":2,"./jsonrpc":10}],13:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1119,25 +1306,29 @@ module.exports = ProviderManager; You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file qtsync.js +/** @file shh.js * @authors: * Marek Kotewicz - * Marian Oancea - * @date 2014 + * @date 2015 */ -var QtSyncProvider = function () { +/// @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' } + ]; }; -QtSyncProvider.prototype.send = function (payload) { - var result = navigator.qt.callMethod(JSON.stringify(payload)); - return JSON.parse(result); +module.exports = { + methods: methods }; -module.exports = QtSyncProvider; - -},{}],11:[function(require,module,exports){ +},{}],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,7 @@ module.exports = { }; -},{"./const":2}],13:[function(require,module,exports){ +},{"./const":2}],16:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1379,102 +1571,14 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file web3.js +/** @file watches.js * @authors: - * Jeffrey Wilcke * Marek Kotewicz - * Marian Oancea - * Gav Wood - * @date 2014 + * @date 2015 */ -if ("build" !== 'build') {/* - var BigNumber = require('bignumber.js'); -*/} - -var utils = require('./utils'); - -/// @returns an array of objects describing web3 api methods -var web3Methods = function () { - return [ - { name: 'sha3', call: 'web3_sha3' } - ]; -}; - -/// @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 eth = function () { var newFilter = function (args) { return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; }; @@ -1487,7 +1591,7 @@ var ethWatchMethods = function () { }; /// @returns an array of objects describing web3.shh.watch api methods -var shhWatchMethods = function () { +var shh = function () { return [ { name: 'newFilter', call: 'shh_newFilter' }, { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, @@ -1495,6 +1599,57 @@ var shhWatchMethods = function () { ]; }; +module.exports = { + eth: eth, + shh: shh +}; + + +},{}],17:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file web3.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Gav Wood + * @date 2014 + */ + +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 () { + return [ + { name: 'sha3', call: 'web3_sha3' } + ]; +}; + /// creates methods in a given object based on method description on input /// setups api calls for these methods var setupMethods = function (obj, methods) { @@ -1502,7 +1657,7 @@ var setupMethods = function (obj, methods) { obj[method.name] = function () { var args = Array.prototype.slice.call(arguments); var call = typeof method.call === 'function' ? method.call(args) : method.call; - return web3.provider.send({ + return web3.manager.send({ method: call, params: args }); @@ -1516,14 +1671,14 @@ var setupProperties = function (obj, properties) { properties.forEach(function (property) { var proto = {}; proto.get = function () { - return web3.provider.send({ + return web3.manager.send({ method: property.getter }); }; if (property.setter) { proto.set = function (val) { - return web3.provider.send({ + return web3.manager.send({ method: property.setter, params: [val] }); @@ -1533,10 +1688,32 @@ var setupProperties = function (obj, properties) { }); }; +/*jshint maxparams:4 */ +var startPolling = function (method, id, callback, uninstall) { + web3.manager.startPolling({ + method: method, + params: [id] + }, id, callback, uninstall); +}; +/*jshint maxparams:3 */ + +var stopPolling = function (id) { + web3.manager.stopPolling(id); +}; + +var ethWatch = { + startPolling: startPolling.bind(null, 'eth_changed'), + stopPolling: stopPolling +}; + +var shhWatch = { + startPolling: startPolling.bind(null, 'shh_changed'), + stopPolling: stopPolling +}; + /// setups web3 object, and it's in-browser executed methods var web3 = { - _callbacks: {}, - _events: {}, + manager: requestManager(), providers: {}, /// @returns ascii string representation of hex value prefixed with 0x @@ -1575,12 +1752,15 @@ var web3 = { /// @param filter may be a string, object or event /// @param indexed is optional, this is an object with optional event indexed params /// @param options is optional, this is an object with optional event options ('max'...) - watch: function (filter, indexed, options) { - if (filter._isEvent) { - return filter(indexed, options); + /// TODO: fix it, 4 params? no way + /*jshint maxparams:4 */ + watch: function (fil, indexed, options, formatter) { + if (fil._isEvent) { + return fil(indexed, options); } - return new web3.filter(filter, ethWatch); + return filter(fil, ethWatch, formatter); } + /*jshint maxparams:3 */ }, /// db object prototype @@ -1588,54 +1768,44 @@ var web3 = { /// shh object prototype shh: { - /// @param filter may be a string, object or event - watch: function (filter, indexed) { - return new web3.filter(filter, shhWatch); + watch: function (fil) { + return filter(fil, shhWatch); } }, + setProvider: function (provider) { + web3.manager.setProvider(provider); + }, + + /// Should be called to reset state of web3 object + /// Resets everything except manager + reset: function () { + web3.manager.reset(); + } }; /// setups all api methods setupMethods(web3, web3Methods()); -setupMethods(web3.eth, ethMethods()); -setupProperties(web3.eth, ethProperties()); -setupMethods(web3.db, dbMethods()); -setupMethods(web3.shh, shhMethods()); - -var ethWatch = { - changed: 'eth_changed' -}; - -setupMethods(ethWatch, ethWatchMethods()); - -var shhWatch = { - changed: 'shh_changed' -}; - -setupMethods(shhWatch, shhWatchMethods()); - -web3.setProvider = function(provider) { - web3.provider.set(provider); -}; +setupMethods(web3.eth, eth.methods()); +setupProperties(web3.eth, eth.properties()); +setupMethods(web3.db, db.methods()); +setupMethods(web3.shh, shh.methods()); +setupMethods(ethWatch, watches.eth()); +setupMethods(shhWatch, watches.shh()); module.exports = web3; -},{"./utils":12}],"web3":[function(require,module,exports){ +},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],"web3":[function(require,module,exports){ var web3 = require('./lib/web3'); -var ProviderManager = require('./lib/providermanager'); -web3.provider = new ProviderManager(); -web3.filter = require('./lib/filter'); web3.providers.HttpSyncProvider = require('./lib/httpsync'); web3.providers.QtSyncProvider = require('./lib/qtsync'); web3.eth.contract = require('./lib/contract'); web3.abi = require('./lib/abi'); - module.exports = web3; -},{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"]) +},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]) //# sourceMappingURL=ethereum.js.map diff --git a/rpc/api.go b/rpc/api.go index 3b4a914efb..28024c2062 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -52,19 +52,20 @@ type EthereumApi struct { db ethutil.Database - defaultBlockAge int + defaultBlockAge int64 } func NewEthereumApi(eth *xeth.XEth) *EthereumApi { db, _ := ethdb.NewLDBDatabase("dapps") api := &EthereumApi{ - 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, + 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() @@ -72,6 +73,22 @@ 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{}) @@ -83,12 +100,7 @@ done: switch ev.(type) { case core.ChainEvent: if self.defaultBlockAge < 0 { - chain := self.xeth().Backend().ChainManager() - block := chain.GetBlockByNumber(chain.CurrentBlock().Number().Uint64() - uint64(self.defaultBlockAge)) - if block != nil { - statedb := state.New(block.Root(), self.db) - self.useState(statedb) - } + self.setStateByBlockNumber(self.defaultBlockAge) } } case <-timer.C: @@ -239,21 +251,6 @@ func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { return nil } -/* -func unlockAccount(server, account *Account) bool { - pwd, status := server.PasswordDialog() - switch status { - case Ok: - if !account.Unlock([]byte(pwd)) { - return unlockAccount(account) - } - return true - default: - return false - } -} -*/ - func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if len(args.Gas) == 0 { args.Gas = defaultGas.String() @@ -378,8 +375,10 @@ func (p *EthereumApi) GetDefaultBlockAge(reply *interface{}) error { return nil } -func (p *EthereumApi) SetDefaultBlockAge(defaultBlockAge int, reply *interface{}) error { +func (p *EthereumApi) SetDefaultBlockAge(defaultBlockAge int64, reply *interface{}) error { p.defaultBlockAge = defaultBlockAge + p.setStateByBlockNumber(p.defaultBlockAge) + *reply = true return nil } @@ -531,7 +530,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error if err != nil { return err } - return p.SetDefaultBlockAge(args, reply) + return p.SetDefaultBlockAge(int64(args), reply) case "eth_peerCount": return p.GetPeerCount(reply) case "eth_number": @@ -720,7 +719,7 @@ func (self *EthereumApi) useState(statedb *state.StateDB) { self.xethMu.Lock() defer self.xethMu.Unlock() - self.eth = self.xeth().UseState(statedb) + self.eth = self.eth.UseState(statedb) } func t(f ui.Frontend) { From e235b57234a68a8a39cfe7691a1825d8c6bb3443 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 18:39:05 +0100 Subject: [PATCH 76/78] Fixed consensus issue for refunding * Refund should _always_ go to the origin --- core/block_processor.go | 8 ++++---- core/state_transition.go | 9 ++++++--- miner/worker.go | 4 ++-- state/dump.go | 2 +- state/state_object.go | 21 +++++++++++++++------ vm/vm.go | 5 +++-- 6 files changed, 31 insertions(+), 18 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index f66d158b2f..7eaeb5be09 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -48,9 +48,8 @@ type BlockProcessor struct { func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor { sm := &BlockProcessor{ - db: db, - mem: make(map[string]*big.Int), - //Pow: ðash.Ethash{}, + db: db, + mem: make(map[string]*big.Int), Pow: ezp.New(), bc: chainManager, eventMux: eventMux, @@ -100,7 +99,8 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated // Notify all subscribers if !transientProcess { go self.eventMux.Post(TxPostEvent{tx}) - go self.eventMux.Post(statedb.Logs()) + logs := statedb.Logs() + go self.eventMux.Post(logs) } return receipt, txGas, err diff --git a/core/state_transition.go b/core/state_transition.go index 36ffa23d9f..a065c4f6bc 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -126,7 +126,7 @@ func (self *StateTransition) BuyGas() error { self.AddGas(self.msg.Gas()) self.initialGas.Set(self.msg.Gas()) - sender.SubAmount(MessageGasValue(self.msg)) + sender.SubBalance(MessageGasValue(self.msg)) return nil } @@ -251,13 +251,16 @@ 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) + fmt.Println("REFUND:", remaining) + sender.AddBalance(remaining) uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2) for addr, ref := range self.state.Refunds() { refund := ethutil.BigMin(uhalf, ref) self.gas.Add(self.gas, refund) - self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice())) + addToIt := refund.Mul(refund, self.msg.GasPrice()) + fmt.Println("ADD TO IT", addToIt) + self.state.AddBalance([]byte(addr), addToIt) } coinbase.RefundGas(self.gas, self.msg.GasPrice()) diff --git a/miner/worker.go b/miner/worker.go index 1f3a52ab52..4f0909302c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -197,7 +197,7 @@ gasLimit: } self.eth.TxPool().RemoveSet(remove) - self.current.coinbase.AddAmount(core.BlockReward) + self.current.coinbase.AddBalance(core.BlockReward) self.current.state.Update(ethutil.Big0) self.push() @@ -225,7 +225,7 @@ func (self *worker) commitUncle(uncle *types.Header) error { } uncleAccount := self.current.state.GetAccount(uncle.Coinbase) - uncleAccount.AddAmount(uncleReward) + uncleAccount.AddBalance(uncleReward) self.current.coinbase.AddBalance(uncleReward) diff --git a/state/dump.go b/state/dump.go index 81895f1a37..073f89414a 100644 --- a/state/dump.go +++ b/state/dump.go @@ -35,7 +35,7 @@ func (self *StateDB) Dump() []byte { storageIt := stateObject.State.trie.Iterator() for storageIt.Next() { - account.Storage[ethutil.Bytes2Hex(it.Key)] = ethutil.Bytes2Hex(it.Value) + account.Storage[ethutil.Bytes2Hex(storageIt.Key)] = ethutil.Bytes2Hex(storageIt.Value) } world.Accounts[ethutil.Bytes2Hex(it.Key)] = account } diff --git a/state/state_object.go b/state/state_object.go index 477b912a12..487952a022 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -19,6 +19,14 @@ func (self Code) String() string { type Storage map[string]*ethutil.Value +func (self Storage) String() (str string) { + for key, value := range self { + str += fmt.Sprintf("%X : %X\n", key, value.Bytes()) + } + + return +} + func (self Storage) Copy() Storage { cpy := make(Storage) for key, value := range self { @@ -119,10 +127,9 @@ func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value { } func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) { self.SetState(key.Bytes(), value) - self.dirty = true } -func (self *StateObject) Storage() map[string]*ethutil.Value { +func (self *StateObject) Storage() Storage { return self.storage } @@ -172,20 +179,22 @@ func (c *StateObject) AddBalance(amount *big.Int) { statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount) } -func (c *StateObject) AddAmount(amount *big.Int) { c.AddBalance(amount) } func (c *StateObject) SubBalance(amount *big.Int) { c.SetBalance(new(big.Int).Sub(c.balance, amount)) statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount) } -func (c *StateObject) SubAmount(amount *big.Int) { c.SubBalance(amount) } func (c *StateObject) SetBalance(amount *big.Int) { c.balance = amount c.dirty = true } +func (c *StateObject) St() Storage { + return c.storage +} + // // Gas setters and getters // @@ -198,7 +207,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { return fmt.Errorf("insufficient amount: %v, %v", c.balance, total) } - c.SubAmount(total) + c.SubBalance(total) c.dirty = true @@ -221,7 +230,7 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { rGas := new(big.Int).Set(gas) rGas.Mul(rGas, price) - self.AddAmount(rGas) + self.AddBalance(rGas) self.dirty = true diff --git a/vm/vm.go b/vm/vm.go index f9efeed96b..7aeeea6619 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -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 @@ -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 { From 3ab05ddd25aa805510ac304c1fd8f7c5c620dff4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 20:26:37 +0100 Subject: [PATCH 77/78] Bump --- cmd/ethereum/main.go | 2 +- cmd/mist/assets/qml/main.qml | 2 +- cmd/mist/main.go | 2 +- core/state_transition.go | 5 +---- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 9c840de589..45e6f7b935 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -37,7 +37,7 @@ import ( const ( ClientIdentifier = "Ethereum(G)" - Version = "0.8.5" + Version = "0.8.6" ) var clilogger = logger.NewLogger("CLI") diff --git a/cmd/mist/assets/qml/main.qml b/cmd/mist/assets/qml/main.qml index e80bd87e09..a909916b7e 100644 --- a/cmd/mist/assets/qml/main.qml +++ b/cmd/mist/assets/qml/main.qml @@ -964,7 +964,7 @@ ApplicationWindow { anchors.top: parent.top anchors.topMargin: 30 font.pointSize: 12 - text: "

Mist (0.8.5)


Development

Jeffrey Wilcke
Viktor Trón
Felix Lange
Taylor Gerring
Daniel Nagy
Gustav Simonsson

UX/UI

Alex van de Sande
Fabian Vogelsteller" + text: "

Mist (0.8.6)


Development

Jeffrey Wilcke
Viktor Trón
Felix Lange
Taylor Gerring
Daniel Nagy
Gustav Simonsson

UX/UI

Alex van de Sande
Fabian Vogelsteller" } } diff --git a/cmd/mist/main.go b/cmd/mist/main.go index ad6eb5becb..3abe167671 100644 --- a/cmd/mist/main.go +++ b/cmd/mist/main.go @@ -36,7 +36,7 @@ import ( const ( ClientIdentifier = "Mist" - Version = "0.8.5" + Version = "0.8.6" ) var ethereum *eth.Ethereum diff --git a/core/state_transition.go b/core/state_transition.go index a065c4f6bc..7331fdd4a5 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -251,16 +251,13 @@ func (self *StateTransition) RefundGas() { coinbase, sender := self.Coinbase(), self.From() // Return remaining gas remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice()) - fmt.Println("REFUND:", remaining) sender.AddBalance(remaining) uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2) for addr, ref := range self.state.Refunds() { refund := ethutil.BigMin(uhalf, ref) self.gas.Add(self.gas, refund) - addToIt := refund.Mul(refund, self.msg.GasPrice()) - fmt.Println("ADD TO IT", addToIt) - self.state.AddBalance([]byte(addr), addToIt) + self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice())) } coinbase.RefundGas(self.gas, self.msg.GasPrice()) From cc5c8a444dbc23501ba1a131eb2334f4b5e1ce9f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 20:36:54 +0100 Subject: [PATCH 78/78] Report proper database directory. Closes #397 --- eth/backend.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/backend.go b/eth/backend.go index 0e5d244297..f67f9c78b0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -147,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