Merge branch 'release/poc5-rc4'

pull/84/head poc5-rc4
obscuren 11 years ago
commit 1adfc272a8
  1. 17
      ethereal/assets/ext/ethereum.js
  2. 262
      ethereal/assets/qml/first_run.qml
  3. 27
      ethereal/assets/qml/webapp.qml
  4. 43
      ethereal/assets/util/test.html
  5. 2
      ethereal/config.go
  6. 14
      ethereal/ethereum.go
  7. 2
      ethereal/ui/ext_app.go
  8. 117
      ethereal/ui/gui.go
  9. 2
      ethereum/config.go
  10. 2
      ethereum/dev_console.go
  11. 48
      ethereum/ethereum.go

@ -36,6 +36,21 @@ window.eth = {
postData({call: "getKey"}, cb); postData({call: "getKey"}, cb);
}, },
getTxCountAt: function(address, cb) {
postData({call: "getTxCountAt", args: [address]}, cb);
},
getIsMining: function(cb){
postData({call: "getIsMining"}, cb)
},
getIsListening: function(cb){
postData({call: "getIsListening"}, cb)
},
getCoinBase: function(cb){
postData({call: "getCoinBase"}, cb);
},
getPeerCount: function(cb){
postData({call: "getPeerCount"}, cb);
},
getBalanceAt: function(address, cb) { getBalanceAt: function(address, cb) {
postData({call: "getBalance", args: [address]}, cb); postData({call: "getBalance", args: [address]}, cb);
}, },
@ -115,6 +130,8 @@ window.eth = {
} }
} }
}, },
} }
window.eth._callbacks = {} window.eth._callbacks = {}
window.eth._onCallbacks = {} window.eth._onCallbacks = {}

@ -10,146 +10,146 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
ApplicationWindow { ApplicationWindow {
id: wizardRoot id: wizardRoot
width: 500 width: 500
height: 400 height: 400
title: "Ethereal first run setup" title: "Ethereal first run setup"
Column { Column {
spacing: 5 spacing: 5
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.left: parent.left anchors.left: parent.left
Text { Text {
visible: true visible: true
text: "<h2>Ethereal setup</h2>" text: "<h2>Ethereal setup</h2>"
} }
Column { Column {
id: restoreColumn id: restoreColumn
spacing: 5 spacing: 5
Text { Text {
visible: true visible: true
font.pointSize: 14 font.pointSize: 14
text: "Restore your Ethereum account" text: "Restore your Ethereum account"
id: restoreLabel id: restoreLabel
} }
TextField { TextField {
id: txPrivKey id: txPrivKey
width: 480 width: 480
placeholderText: "Private key or mnemonic words" placeholderText: "Private key or mnemonic words"
focus: true focus: true
onTextChanged: { onTextChanged: {
if(this.text.length == 64){ if(this.text.length == 64){
detailLabel.text = "Private (hex) key detected." detailLabel.text = "Private (hex) key detected."
actionButton.enabled = true actionButton.enabled = true
} }
else if(this.text.split(" ").length == 24){ else if(this.text.split(" ").length == 24){
detailLabel.text = "Mnemonic key detected." detailLabel.text = "Mnemonic key detected."
actionButton.enabled = true actionButton.enabled = true
}else{ }else{
detailLabel.text = "" detailLabel.text = ""
actionButton.enabled = false actionButton.enabled = false
} }
}
}
Row {
spacing: 10
Button {
id: actionButton
text: "Restore"
enabled: false
onClicked: {
var success = lib.importAndSetPrivKey(txPrivKey.text)
if(success){
importedDetails.visible = true
restoreColumn.visible = false
newKey.visible = false
wizardRoot.height = 120
}
}
}
Text {
id: detailLabel
font.pointSize: 12
anchors.topMargin: 10
}
}
} }
} Column {
Row { id: importedDetails
spacing: 10 visible: false
Button { Text {
id: actionButton text: "<b>Your account has been imported. Please close the application and restart it again to let the changes take effect.</b>"
text: "Restore" wrapMode: Text.WordWrap
enabled: false width: 460
onClicked: { }
var success = eth.importAndSetPrivKey(txPrivKey.text)
if(success){
importedDetails.visible = true
restoreColumn.visible = false
newKey.visible = false
wizardRoot.height = 120
}
}
} }
Text { Column {
id: detailLabel spacing: 5
font.pointSize: 12 id: newDetailsColumn
anchors.topMargin: 10 visible: false
Text {
font.pointSize: 14
text: "Your account details"
}
Label {
text: "Address"
}
TextField {
id: addressInput
readOnly:true
width: 480
}
Label {
text: "Private key"
}
TextField {
id: privkeyInput
readOnly:true
width: 480
}
Label {
text: "Mnemonic words"
}
TextField {
id: mnemonicInput
readOnly:true
width: 480
}
Label {
text: "<b>A new account has been created. Please take the time to write down the <i>24 words</i>. You can use those to restore your account at a later date.</b>"
wrapMode: Text.WordWrap
width: 480
}
Label {
text: "Please restart the application once you have completed the steps above."
wrapMode: Text.WordWrap
width: 480
}
} }
}
}
Column {
id: importedDetails
visible: false
Text {
text: "<b>Your account has been imported. Please close the application and restart it again to let the changes take effect.</b>"
wrapMode: Text.WordWrap
width: 460
}
}
Column {
spacing: 5
id: newDetailsColumn
visible: false
Text {
font.pointSize: 14
text: "Your account details"
}
Label {
text: "Address"
}
TextField {
id: addressInput
readOnly:true
width: 480
}
Label {
text: "Private key"
}
TextField {
id: privkeyInput
readOnly:true
width: 480
}
Label {
text: "Mnemonic words"
}
TextField {
id: mnemonicInput
readOnly:true
width: 480
}
Label {
text: "<b>A new account has been created. Please take the time to write down the <i>24 words</i>. You can use those to restore your account at a later date.</b>"
wrapMode: Text.WordWrap
width: 480
}
Label {
text: "Please restart the application once you have completed the steps above."
wrapMode: Text.WordWrap
width: 480
}
}
} }
Button { Button {
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.rightMargin: 10 anchors.rightMargin: 10
anchors.bottomMargin: 10 anchors.bottomMargin: 10
id: newKey id: newKey
text: "I don't have an account yet" text: "I don't have an account yet"
onClicked: { onClicked: {
var res = eth.createAndSetPrivKey() var res = lib.createAndSetPrivKey()
mnemonicInput.text = res[0] mnemonicInput.text = res[0]
addressInput.text = res[1] addressInput.text = res[1]
privkeyInput.text = res[2] privkeyInput.text = res[2]
// Hide restore // Hide restore
restoreColumn.visible = false restoreColumn.visible = false
// Show new details // Show new details
newDetailsColumn.visible = true newDetailsColumn.visible = true
newKey.visible = false newKey.visible = false
}
} }
}
} }

@ -47,13 +47,37 @@ ApplicationWindow {
try { try {
switch(data.call) { switch(data.call) {
case "getCoinBase":
postData(data._seed, eth.getCoinBase())
break
case "getIsListening":
postData(data._seed, eth.getIsListening())
break
case "getIsMining":
postData(data._seed, eth.getIsMining())
break
case "getPeerCount":
postData(data._seed, eth.getPeerCount())
break
case "getTxCountAt":
require(1)
postData(data._seed, eth.getTxCountAt(data.args[0]))
break
case "getBlockByNumber": case "getBlockByNumber":
var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06") var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06")
postData(data._seed, block) postData(data._seed, block)
break break
case "getBlockByHash": case "getBlockByHash":
var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06") var block = eth.getBlock("b9b56cf6f907fbee21db0cd7cbc0e6fea2fe29503a3943e275c5e467d649cb06")
postData(data._seed, block) postData(data._seed, block)
break break
case "transact": case "transact":
require(5) require(5)
@ -94,11 +118,14 @@ ApplicationWindow {
postData(data._seed, null) postData(data._seed, null)
break; break;
case "set": case "set":
console.log("'Set' has been depcrecated")
/*
for(var key in data.args) { for(var key in data.args) {
if(webview.hasOwnProperty(key)) { if(webview.hasOwnProperty(key)) {
window[key] = data.args[key]; window[key] = data.args[key];
} }
} }
*/
break; break;
case "getSecretToAddress": case "getSecretToAddress":
require(1) require(1)

@ -0,0 +1,43 @@
<html>
<head>
<title>Utils</title>
</head>
<body onload="init();">
<label>Nonce for 2ef47100e0787b915105fd5e3f4ff6752079d5cb</label>
<p id="nonce"></p>
<label>Connected peers</label>
<p id="peers"></p>
<label>Is mining</label>
<p id="isMining"></p>
<label>Is listening</label>
<p id="isListen"></p>
<label>Coinbase</label>
<p id="coinbase"></p>
<script type="text/javascript">
function init() {
eth.getTxCountAt("2ef47100e0787b915105fd5e3f4ff6752079d5cb", function(nonce){
document.querySelector("#nonce").innerHTML = nonce;
})
eth.getPeerCount(function(peerLength){
document.querySelector("#peers").innerHTML = peerLength;
})
eth.getIsMining(function(mining){
document.querySelector("#isMining").innerHTML = mining;
})
eth.getIsListening(function(listen){
document.querySelector("#isListen").innerHTML = listen;
})
eth.getCoinBase(function(address){
document.querySelector("#coinbase").innerHTML = address;
})
}
</script>
</body>
</html>

@ -7,6 +7,7 @@ import (
var StartConsole bool var StartConsole bool
var StartMining bool var StartMining bool
var StartRpc bool var StartRpc bool
var RpcPort int
var UseUPnP bool var UseUPnP bool
var OutboundPort string var OutboundPort string
var ShowGenesis bool var ShowGenesis bool
@ -28,6 +29,7 @@ func Init() {
flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key") flag.BoolVar(&ExportKey, "export", false, "export private key")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.StringVar(&OutboundPort, "p", "30303", "listening port") flag.StringVar(&OutboundPort, "p", "30303", "listening port")
flag.StringVar(&DataDir, "dir", ".ethereal", "ethereum data directory") flag.StringVar(&DataDir, "dir", ".ethereal", "ethereum data directory")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")

@ -100,8 +100,12 @@ func main() {
} }
if StartRpc { if StartRpc {
ethereum.RpcServer = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum.StateManager(), ethereum.BlockChain(), ethereum.TxPool())) ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
go ethereum.RpcServer.Start() if err != nil {
log.Println("Could not start RPC interface:", err)
} else {
go ethereum.RpcServer.Start()
}
} }
log.Printf("Starting Ethereum GUI v%s\n", ethutil.Config.Ver) log.Printf("Starting Ethereum GUI v%s\n", ethutil.Config.Ver)
@ -110,5 +114,11 @@ func main() {
ethereum.MaxPeers = MaxPeer ethereum.MaxPeers = MaxPeer
gui := ethui.New(ethereum) gui := ethui.New(ethereum)
ethereum.Start(UseSeed)
gui.Start(AssetPath) gui.Start(AssetPath)
// Wait for shutdown
ethereum.WaitForShutdown()
} }

@ -34,7 +34,7 @@ type ExtApplication struct {
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication { func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication {
app := &ExtApplication{ app := &ExtApplication{
ethpub.NewPEthereum(lib.eth.StateManager(), lib.eth.BlockChain(), lib.eth.TxPool()), ethpub.NewPEthereum(lib.eth),
make(chan ethutil.React, 1), make(chan ethutil.React, 1),
make(chan ethutil.React, 1), make(chan ethutil.React, 1),
make(chan bool), make(chan bool),

@ -24,7 +24,8 @@ type Gui struct {
eth *eth.Ethereum eth *eth.Ethereum
// The public Ethereum library // The public Ethereum library
lib *EthLib lib *EthLib
uiLib *UiLib
txDb *ethdb.LDBDatabase txDb *ethdb.LDBDatabase
@ -52,7 +53,7 @@ func New(ethereum *eth.Ethereum) *Gui {
//ethereum.StateManager().WatchAddr(addr) //ethereum.StateManager().WatchAddr(addr)
} }
pub := ethpub.NewPEthereum(ethereum.StateManager(), ethereum.BlockChain(), ethereum.TxPool()) pub := ethpub.NewPEthereum(ethereum)
return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr, pub: pub} return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr, pub: pub}
} }
@ -67,7 +68,7 @@ func (gui *Gui) Start(assetPath string) {
Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" }, Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
}}) }})
ethutil.Config.SetClientString(fmt.Sprintf("/Ethereal v%s", "0.5.0 RC3")) ethutil.Config.SetClientString(fmt.Sprintf("/Ethereal v%s", "0.5.0 RC4"))
ethutil.Config.Log.Infoln("[GUI] Starting GUI") ethutil.Config.Log.Infoln("[GUI] Starting GUI")
// Create a new QML engine // Create a new QML engine
gui.engine = qml.NewEngine() gui.engine = qml.NewEngine()
@ -75,19 +76,55 @@ func (gui *Gui) Start(assetPath string) {
// Expose the eth library and the ui library to QML // Expose the eth library and the ui library to QML
context.SetVar("eth", gui) context.SetVar("eth", gui)
uiLib := NewUiLib(gui.engine, gui.eth, assetPath) gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath)
context.SetVar("ui", uiLib) context.SetVar("ui", gui.uiLib)
// Load the main QML interface // Load the main QML interface
data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
var err error /*
var component qml.Object var err error
firstRun := len(data) == 0 var component qml.Object
firstRun := len(data) == 0
if firstRun {
component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/first_run.qml"))
} else {
component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/wallet.qml"))
}
if err != nil {
ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'")
panic(err)
}
gui.win = component.CreateWindow(nil)
uiLib.win = gui.win
db := &Debugger{gui.win, make(chan bool)}
gui.lib.Db = db
uiLib.Db = db
// Add the ui as a log system so we can log directly to the UGI
ethutil.Config.Log.AddLogSystem(gui)
// Loads previous blocks
if firstRun == false {
go gui.setInitialBlockChain()
go gui.readPreviousTransactions()
go gui.update()
}
if firstRun { gui.win.Show()
component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/first_run.qml")) gui.win.Wait()
gui.eth.Stop()
*/
var win *qml.Window
var err error
if len(data) == 0 {
win, err = gui.showKeyImport(context)
} else { } else {
component, err = gui.engine.LoadFile(uiLib.AssetPath("qml/wallet.qml")) win, err = gui.showWallet(context)
} }
if err != nil { if err != nil {
ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'") ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'")
@ -95,26 +132,48 @@ func (gui *Gui) Start(assetPath string) {
panic(err) panic(err)
} }
gui.win = component.CreateWindow(nil) win.Show()
uiLib.win = gui.win win.Wait()
db := &Debugger{gui.win, make(chan bool)}
gui.lib.Db = db gui.eth.Stop()
uiLib.Db = db }
func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/wallet.qml"))
if err != nil {
return nil, err
}
// Add the ui as a log system so we can log directly to the UGI win := gui.createWindow(component)
ethutil.Config.Log.AddLogSystem(gui)
// Loads previous blocks go gui.setInitialBlockChain()
if firstRun == false { go gui.readPreviousTransactions()
go gui.setInitialBlockChain() go gui.update()
go gui.readPreviousTransactions()
go gui.update() return win, nil
}
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
context.SetVar("lib", gui.lib)
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/first_run.qml"))
if err != nil {
return nil, err
} }
gui.win.Show() return gui.createWindow(component), nil
gui.win.Wait() }
gui.eth.Stop() func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
win := comp.CreateWindow(nil)
gui.win = win
gui.uiLib.win = win
db := &Debugger{gui.win, make(chan bool)}
gui.lib.Db = db
gui.uiLib.Db = db
return gui.win
} }
func (gui *Gui) setInitialBlockChain() { func (gui *Gui) setInitialBlockChain() {
@ -148,7 +207,7 @@ func (gui *Gui) update() {
state := gui.eth.StateManager().TransState() state := gui.eth.StateManager().TransState()
unconfirmedFunds := new(big.Int) unconfirmedFunds := new(big.Int)
gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetStateObject(gui.addr).Amount))) gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.addr).Amount)))
for { for {
select { select {
@ -156,7 +215,7 @@ func (gui *Gui) update() {
tx := txMsg.Tx tx := txMsg.Tx
if txMsg.Type == ethchain.TxPre { if txMsg.Type == ethchain.TxPre {
object := state.GetStateObject(gui.addr) object := state.GetAccount(gui.addr)
if bytes.Compare(tx.Sender(), gui.addr) == 0 && object.Nonce <= tx.Nonce { if bytes.Compare(tx.Sender(), gui.addr) == 0 && object.Nonce <= tx.Nonce {
gui.win.Root().Call("addTx", ethpub.NewPTx(tx)) gui.win.Root().Call("addTx", ethpub.NewPTx(tx))
@ -182,7 +241,7 @@ func (gui *Gui) update() {
gui.win.Root().Call("setWalletValue", str) gui.win.Root().Call("setWalletValue", str)
} else { } else {
object := state.GetStateObject(gui.addr) object := state.GetAccount(gui.addr)
if bytes.Compare(tx.Sender(), gui.addr) == 0 { if bytes.Compare(tx.Sender(), gui.addr) == 0 {
object.SubAmount(tx.Value) object.SubAmount(tx.Value)
} else if bytes.Compare(tx.Recipient, gui.addr) == 0 { } else if bytes.Compare(tx.Recipient, gui.addr) == 0 {

@ -7,6 +7,7 @@ import (
var StartConsole bool var StartConsole bool
var StartMining bool var StartMining bool
var StartRpc bool var StartRpc bool
var RpcPort int
var UseUPnP bool var UseUPnP bool
var OutboundPort string var OutboundPort string
var ShowGenesis bool var ShowGenesis bool
@ -26,6 +27,7 @@ func Init() {
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits") flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits")
//flag.BoolVar(&UseGui, "gui", true, "use the gui") //flag.BoolVar(&UseGui, "gui", true, "use the gui")
flag.BoolVar(&StartRpc, "r", false, "start rpc server") flag.BoolVar(&StartRpc, "r", false, "start rpc server")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)") flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support") flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.BoolVar(&UseSeed, "seed", true, "seed peers") flag.BoolVar(&UseSeed, "seed", true, "seed peers")

@ -191,7 +191,7 @@ func (i *Console) ParseInput(input string) bool {
case "contract": case "contract":
fmt.Println("Contract editor (Ctrl-D = done)") fmt.Println("Contract editor (Ctrl-D = done)")
mainInput, initInput := mutan.PreProcess(i.Editor()) mainInput, initInput := mutan.PreParse(i.Editor())
mainScript, err := utils.Compile(mainInput) mainScript, err := utils.Compile(mainInput)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/hex"
"fmt" "fmt"
"github.com/ethereum/eth-go" "github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
@ -122,24 +123,8 @@ func main() {
// Set the max peers // Set the max peers
ethereum.MaxPeers = MaxPeer ethereum.MaxPeers = MaxPeer
if StartConsole { // Set Mining status
err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm) ethereum.Mining = StartMining
// Error is OK if the error is ErrExist
if err != nil && !os.IsExist(err) {
log.Panic("Unable to create EXECPATH:", err)
}
console := NewConsole(ethereum)
go console.Start()
}
if StartRpc {
ethereum.RpcServer = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum.StateManager(), ethereum.BlockChain(), ethereum.TxPool()))
go ethereum.RpcServer.Start()
}
RegisterInterrupts(ethereum)
ethereum.Start(UseSeed)
if StartMining { if StartMining {
logger.Infoln("Miner started") logger.Infoln("Miner started")
@ -155,7 +140,9 @@ func main() {
keyRing := ethutil.NewValueFromBytes(data) keyRing := ethutil.NewValueFromBytes(data)
addr := keyRing.Get(1).Bytes() addr := keyRing.Get(1).Bytes()
miner := ethminer.NewDefaultMiner(addr, ethereum) pair, _ := ethchain.NewKeyPairFromSec(ethutil.FromHex(hex.EncodeToString(addr)))
miner := ethminer.NewDefaultMiner(pair.Address(), ethereum)
miner.Start() miner.Start()
}() }()
@ -164,6 +151,29 @@ func main() {
} }
if StartConsole {
err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm)
// Error is OK if the error is ErrExist
if err != nil && !os.IsExist(err) {
log.Panic("Unable to create EXECPATH:", err)
}
console := NewConsole(ethereum)
go console.Start()
}
if StartRpc {
ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
if err != nil {
logger.Infoln("Could not start RPC interface:", err)
} else {
go ethereum.RpcServer.Start()
}
}
RegisterInterrupts(ethereum)
ethereum.Start(UseSeed)
// Wait for shutdown // Wait for shutdown
ethereum.WaitForShutdown() ethereum.WaitForShutdown()
} }

Loading…
Cancel
Save