Merge branch 'ethersphere-feature/keys' into develop
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -9,4 +9,3 @@
 | 
			
		||||
*un~
 | 
			
		||||
.DS_Store
 | 
			
		||||
*/**/.DS_Store
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,4 @@
 | 
			
		||||
before_install: sudo apt-get install libgmp3-dev
 | 
			
		||||
language: go
 | 
			
		||||
go:
 | 
			
		||||
  - 1.2
 | 
			
		||||
							
								
								
									
										22
									
								
								ethereal/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
UNAME = $(shell uname)
 | 
			
		||||
FILES=qml *.png
 | 
			
		||||
GOPATH=$(PWD)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Default is building
 | 
			
		||||
all:
 | 
			
		||||
	go get -d
 | 
			
		||||
	cp *.go $(GOPATH)/src/github.com/ethereum/go-ethereum
 | 
			
		||||
	cp -r ui $(GOPATH)/src/github.com/ethereum/go-ethereum
 | 
			
		||||
	go build
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
# Linux build
 | 
			
		||||
ifeq ($(UNAME),Linux)
 | 
			
		||||
	cp -r assets/* /usr/share/ethereal
 | 
			
		||||
	cp go-ethereum /usr/local/bin/ethereal
 | 
			
		||||
endif
 | 
			
		||||
# OS X build
 | 
			
		||||
ifeq ($(UNAME),Darwin)
 | 
			
		||||
	# Execute py script
 | 
			
		||||
endif
 | 
			
		||||
							
								
								
									
										270
									
								
								ethereal/assets/debugger/debugger.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,270 @@
 | 
			
		||||
import QtQuick 2.0
 | 
			
		||||
import QtQuick.Controls 1.0;
 | 
			
		||||
import QtQuick.Layouts 1.0;
 | 
			
		||||
import QtQuick.Dialogs 1.0;
 | 
			
		||||
import QtQuick.Window 2.1;
 | 
			
		||||
import QtQuick.Controls.Styles 1.1
 | 
			
		||||
import Ethereum 1.0
 | 
			
		||||
 | 
			
		||||
ApplicationWindow {
 | 
			
		||||
	visible: false
 | 
			
		||||
	title: "IceCREAM"
 | 
			
		||||
	minimumWidth: 1280
 | 
			
		||||
	minimumHeight: 700
 | 
			
		||||
	width: 1290
 | 
			
		||||
	height: 700
 | 
			
		||||
 | 
			
		||||
	property alias codeText: codeEditor.text
 | 
			
		||||
	property alias dataText: rawDataField.text
 | 
			
		||||
 | 
			
		||||
	MenuBar {
 | 
			
		||||
		Menu {
 | 
			
		||||
			title: "Debugger"
 | 
			
		||||
			MenuItem {
 | 
			
		||||
				text: "Run"
 | 
			
		||||
				shortcut: "Ctrl+r"
 | 
			
		||||
				onTriggered: debugCurrent()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			MenuItem {
 | 
			
		||||
				text: "Next"
 | 
			
		||||
				shortcut: "Ctrl+n"
 | 
			
		||||
				onTriggered: dbg.next()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SplitView {
 | 
			
		||||
		anchors.fill: parent
 | 
			
		||||
		property var asmModel: ListModel {
 | 
			
		||||
			id: asmModel
 | 
			
		||||
		}
 | 
			
		||||
		TableView {
 | 
			
		||||
			id: asmTableView
 | 
			
		||||
			width: 200
 | 
			
		||||
			TableViewColumn{ role: "value" ; title: "" ; width: 200 }
 | 
			
		||||
			model: asmModel
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Rectangle {
 | 
			
		||||
			color: "#00000000"
 | 
			
		||||
			anchors.left: asmTableView.right
 | 
			
		||||
			anchors.right: parent.right
 | 
			
		||||
			SplitView {
 | 
			
		||||
				orientation: Qt.Vertical
 | 
			
		||||
				anchors.fill: parent
 | 
			
		||||
 | 
			
		||||
				Rectangle {
 | 
			
		||||
					color: "#00000000"
 | 
			
		||||
					height: 330
 | 
			
		||||
					anchors.left: parent.left
 | 
			
		||||
					anchors.right: parent.right
 | 
			
		||||
 | 
			
		||||
					TextArea {
 | 
			
		||||
						id: codeEditor
 | 
			
		||||
						anchors.top: parent.top
 | 
			
		||||
						anchors.bottom: parent.bottom
 | 
			
		||||
						anchors.left: parent.left
 | 
			
		||||
						anchors.right: settings.left
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					Column {
 | 
			
		||||
						id: settings
 | 
			
		||||
						spacing: 5
 | 
			
		||||
						width: 300
 | 
			
		||||
						height: parent.height
 | 
			
		||||
						anchors.right: parent.right
 | 
			
		||||
						anchors.top: parent.top
 | 
			
		||||
						anchors.bottom: parent.bottom
 | 
			
		||||
 | 
			
		||||
						Label {
 | 
			
		||||
							text: "Arbitrary data"
 | 
			
		||||
						}
 | 
			
		||||
						TextArea {
 | 
			
		||||
							id: rawDataField
 | 
			
		||||
							anchors.left: parent.left
 | 
			
		||||
							anchors.right: parent.right
 | 
			
		||||
							height: 150
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						Label {
 | 
			
		||||
							text: "Amount"
 | 
			
		||||
						}
 | 
			
		||||
						TextField {
 | 
			
		||||
							id: txValue
 | 
			
		||||
							width: 200
 | 
			
		||||
							placeholderText: "Amount"
 | 
			
		||||
							validator: RegExpValidator { regExp: /\d*/ }
 | 
			
		||||
						}
 | 
			
		||||
						Label {
 | 
			
		||||
							text: "Amount of gas"
 | 
			
		||||
						}
 | 
			
		||||
						TextField {
 | 
			
		||||
							id: txGas
 | 
			
		||||
							width: 200
 | 
			
		||||
							validator: RegExpValidator { regExp: /\d*/ }
 | 
			
		||||
							text: "10000"
 | 
			
		||||
							placeholderText: "Gas"
 | 
			
		||||
						}
 | 
			
		||||
						Label {
 | 
			
		||||
							text: "Gas price"
 | 
			
		||||
						}
 | 
			
		||||
						TextField {
 | 
			
		||||
							id: txGasPrice
 | 
			
		||||
							width: 200
 | 
			
		||||
							placeholderText: "Gas price"
 | 
			
		||||
							text: "1000000000000"
 | 
			
		||||
							validator: RegExpValidator { regExp: /\d*/ }
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				SplitView {
 | 
			
		||||
					orientation: Qt.Vertical
 | 
			
		||||
					id: inspectorPane
 | 
			
		||||
					height: 500
 | 
			
		||||
 | 
			
		||||
					SplitView {
 | 
			
		||||
						orientation: Qt.Horizontal
 | 
			
		||||
						height: 150
 | 
			
		||||
 | 
			
		||||
						TableView {
 | 
			
		||||
							id: stackTableView
 | 
			
		||||
							property var stackModel: ListModel {
 | 
			
		||||
								id: stackModel
 | 
			
		||||
							}
 | 
			
		||||
							height: parent.height
 | 
			
		||||
							width: 300
 | 
			
		||||
							TableViewColumn{ role: "value" ; title: "Temp" ; width: 200 }
 | 
			
		||||
							model: stackModel
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						TableView {
 | 
			
		||||
							id: memoryTableView
 | 
			
		||||
							property var memModel: ListModel {
 | 
			
		||||
								id: memModel
 | 
			
		||||
							}
 | 
			
		||||
							height: parent.height
 | 
			
		||||
							width: parent.width - stackTableView.width
 | 
			
		||||
							TableViewColumn{ id:mnumColmn ; role: "num" ; title: "#" ; width: 50}
 | 
			
		||||
							TableViewColumn{ role: "value" ; title: "Memory" ; width: 750}
 | 
			
		||||
							model: memModel
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					Rectangle {
 | 
			
		||||
						height: 100
 | 
			
		||||
						width: parent.width
 | 
			
		||||
						TableView {
 | 
			
		||||
							id: storageTableView
 | 
			
		||||
							property var memModel: ListModel {
 | 
			
		||||
								id: storageModel
 | 
			
		||||
							}
 | 
			
		||||
							height: parent.height
 | 
			
		||||
							width: parent.width
 | 
			
		||||
							TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2}
 | 
			
		||||
							TableViewColumn{ role: "value" ; title: "Storage" ; width:  storageTableView.width / 2}
 | 
			
		||||
							model: storageModel
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					Rectangle {
 | 
			
		||||
						height: 200
 | 
			
		||||
						width: parent.width
 | 
			
		||||
						TableView {
 | 
			
		||||
							id: logTableView
 | 
			
		||||
							property var logModel: ListModel {
 | 
			
		||||
								id: logModel
 | 
			
		||||
							}
 | 
			
		||||
							height: parent.height
 | 
			
		||||
							width: parent.width
 | 
			
		||||
							TableViewColumn{ id: message ; role: "message" ; title: "log" ; width: logTableView.width }
 | 
			
		||||
							model: logModel
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	toolBar: ToolBar {
 | 
			
		||||
		RowLayout {
 | 
			
		||||
			spacing: 5
 | 
			
		||||
 | 
			
		||||
			Button {
 | 
			
		||||
				property var enabled: true
 | 
			
		||||
				id: debugStart
 | 
			
		||||
				onClicked: {
 | 
			
		||||
					debugCurrent()
 | 
			
		||||
				}
 | 
			
		||||
				text: "Debug"
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Button {
 | 
			
		||||
				property var enabled: true
 | 
			
		||||
				id: debugNextButton
 | 
			
		||||
				onClicked: {
 | 
			
		||||
					dbg.next()
 | 
			
		||||
				}
 | 
			
		||||
				text: "Next"
 | 
			
		||||
			}
 | 
			
		||||
			CheckBox {
 | 
			
		||||
				id: breakEachLine
 | 
			
		||||
				objectName: "breakEachLine"
 | 
			
		||||
				text: "Break each instruction"
 | 
			
		||||
				checked: true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function debugCurrent() {
 | 
			
		||||
		dbg.debug(txValue.text, txGas.text, txGasPrice.text, codeEditor.text, rawDataField.text)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function setAsm(asm) {
 | 
			
		||||
		asmModel.append({asm: asm})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function clearAsm() {
 | 
			
		||||
		asmModel.clear()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function setInstruction(num) {
 | 
			
		||||
		asmTableView.selection.clear()
 | 
			
		||||
		asmTableView.selection.select(num)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function setMem(mem) {
 | 
			
		||||
		memModel.append({num: mem.num, value: mem.value})
 | 
			
		||||
	}
 | 
			
		||||
	function clearMem(){
 | 
			
		||||
		memModel.clear()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function setStack(stack) {
 | 
			
		||||
		stackModel.append({value: stack})
 | 
			
		||||
	}
 | 
			
		||||
	function addDebugMessage(message){
 | 
			
		||||
		debuggerLog.append({value: message})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function clearStack() {
 | 
			
		||||
		stackModel.clear()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function clearStorage() {
 | 
			
		||||
		storageModel.clear()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function setStorage(storage) {
 | 
			
		||||
		storageModel.append({key: storage.key, value: storage.value})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function setLog(msg) {
 | 
			
		||||
		logModel.insert(0, {message: msg})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function clearLog() {
 | 
			
		||||
		logModel.clear()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										380
									
								
								ethereal/assets/ext/big.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,380 @@
 | 
			
		||||
var bigInt = (function () {
 | 
			
		||||
    var base = 10000000, logBase = 7;
 | 
			
		||||
    var sign = {
 | 
			
		||||
        positive: false,
 | 
			
		||||
        negative: true
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var normalize = function (first, second) {
 | 
			
		||||
        var a = first.value, b = second.value;
 | 
			
		||||
        var length = a.length > b.length ? a.length : b.length;
 | 
			
		||||
        for (var i = 0; i < length; i++) {
 | 
			
		||||
            a[i] = a[i] || 0;
 | 
			
		||||
            b[i] = b[i] || 0;
 | 
			
		||||
        }
 | 
			
		||||
        for (var i = length - 1; i >= 0; i--) {
 | 
			
		||||
            if (a[i] === 0 && b[i] === 0) {
 | 
			
		||||
                a.pop();
 | 
			
		||||
                b.pop();
 | 
			
		||||
            } else break;
 | 
			
		||||
        }
 | 
			
		||||
        if (!a.length) a = [0], b = [0];
 | 
			
		||||
        first.value = a;
 | 
			
		||||
        second.value = b;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var parse = function (text, first) {
 | 
			
		||||
        if (typeof text === "object") return text;
 | 
			
		||||
        text += "";
 | 
			
		||||
        var s = sign.positive, value = [];
 | 
			
		||||
        if (text[0] === "-") {
 | 
			
		||||
            s = sign.negative;
 | 
			
		||||
            text = text.slice(1);
 | 
			
		||||
        }
 | 
			
		||||
	var base = 10;
 | 
			
		||||
        if (text.slice(0, 2) == "0x") {
 | 
			
		||||
            base = 16;
 | 
			
		||||
            text = text.slice(2);
 | 
			
		||||
        }
 | 
			
		||||
	else {
 | 
			
		||||
	        var texts = text.split("e");
 | 
			
		||||
		if (texts.length > 2) throw new Error("Invalid integer");
 | 
			
		||||
		if (texts[1]) {
 | 
			
		||||
		    var exp = texts[1];
 | 
			
		||||
		    if (exp[0] === "+") exp = exp.slice(1);
 | 
			
		||||
		    exp = parse(exp);
 | 
			
		||||
		    if (exp.lesser(0)) throw new Error("Cannot include negative exponent part for integers");
 | 
			
		||||
		    while (exp.notEquals(0)) {
 | 
			
		||||
		        texts[0] += "0";
 | 
			
		||||
		        exp = exp.prev();
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
	        text = texts[0];
 | 
			
		||||
	}
 | 
			
		||||
        if (text === "-0") text = "0";
 | 
			
		||||
	text = text.toUpperCase();
 | 
			
		||||
        var isValid = (base == 16 ? /^[0-9A-F]*$/ : /^[0-9]+$/).test(text);
 | 
			
		||||
        if (!isValid) throw new Error("Invalid integer");
 | 
			
		||||
	if (base == 16) {
 | 
			
		||||
		var val = bigInt(0);
 | 
			
		||||
		while (text.length) {
 | 
			
		||||
			v = text.charCodeAt(0) - 48;
 | 
			
		||||
			if (v > 9)
 | 
			
		||||
				v -= 7;
 | 
			
		||||
			text = text.slice(1);
 | 
			
		||||
			val = val.times(16).plus(v);
 | 
			
		||||
		}
 | 
			
		||||
		return val;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		while (text.length) {
 | 
			
		||||
		    var divider = text.length > logBase ? text.length - logBase : 0;
 | 
			
		||||
		    value.push(+text.slice(divider));
 | 
			
		||||
		    text = text.slice(0, divider);
 | 
			
		||||
		}
 | 
			
		||||
	        var val = bigInt(value, s);
 | 
			
		||||
	        if (first) normalize(first, val);
 | 
			
		||||
        	return val;
 | 
			
		||||
	}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var goesInto = function (a, b) {
 | 
			
		||||
        var a = bigInt(a, sign.positive), b = bigInt(b, sign.positive);
 | 
			
		||||
        if (a.equals(0)) throw new Error("Cannot divide by 0");
 | 
			
		||||
        var n = 0;
 | 
			
		||||
        do {
 | 
			
		||||
            var inc = 1;
 | 
			
		||||
            var c = bigInt(a.value, sign.positive), t = c.times(10);
 | 
			
		||||
            while (t.lesser(b)) {
 | 
			
		||||
                c = t;
 | 
			
		||||
                inc *= 10;
 | 
			
		||||
                t = t.times(10);
 | 
			
		||||
            }
 | 
			
		||||
            while (c.lesserOrEquals(b)) {
 | 
			
		||||
                b = b.minus(c);
 | 
			
		||||
                n += inc;
 | 
			
		||||
            }
 | 
			
		||||
        } while (a.lesserOrEquals(b));
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            remainder: b.value,
 | 
			
		||||
            result: n
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var bigInt = function (value, s) {
 | 
			
		||||
        var self = {
 | 
			
		||||
            value: value,
 | 
			
		||||
            sign: s
 | 
			
		||||
        };
 | 
			
		||||
        var o = {
 | 
			
		||||
            value: value,
 | 
			
		||||
            sign: s,
 | 
			
		||||
            negate: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                return bigInt(first.value, !first.sign);
 | 
			
		||||
            },
 | 
			
		||||
            abs: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                return bigInt(first.value, sign.positive);
 | 
			
		||||
            },
 | 
			
		||||
            add: function (n, m) {
 | 
			
		||||
                var s, first = self, second;
 | 
			
		||||
                if (m) (first = parse(n)) && (second = parse(m));
 | 
			
		||||
                else second = parse(n, first);
 | 
			
		||||
                s = first.sign;
 | 
			
		||||
                if (first.sign !== second.sign) {
 | 
			
		||||
                    first = bigInt(first.value, sign.positive);
 | 
			
		||||
                    second = bigInt(second.value, sign.positive);
 | 
			
		||||
                    return s === sign.positive ?
 | 
			
		||||
						o.subtract(first, second) :
 | 
			
		||||
						o.subtract(second, first);
 | 
			
		||||
                }
 | 
			
		||||
                normalize(first, second);
 | 
			
		||||
                var a = first.value, b = second.value;
 | 
			
		||||
                var result = [],
 | 
			
		||||
					carry = 0;
 | 
			
		||||
                for (var i = 0; i < a.length || carry > 0; i++) {
 | 
			
		||||
                    var sum = (a[i] || 0) + (b[i] || 0) + carry;
 | 
			
		||||
                    carry = sum >= base ? 1 : 0;
 | 
			
		||||
                    sum -= carry * base;
 | 
			
		||||
                    result.push(sum);
 | 
			
		||||
                }
 | 
			
		||||
                return bigInt(result, s);
 | 
			
		||||
            },
 | 
			
		||||
            plus: function (n, m) {
 | 
			
		||||
                return o.add(n, m);
 | 
			
		||||
            },
 | 
			
		||||
            subtract: function (n, m) {
 | 
			
		||||
                var first = self, second;
 | 
			
		||||
                if (m) (first = parse(n)) && (second = parse(m));
 | 
			
		||||
                else second = parse(n, first);
 | 
			
		||||
                if (first.sign !== second.sign) return o.add(first, o.negate(second));
 | 
			
		||||
                if (first.sign === sign.negative) return o.subtract(o.negate(second), o.negate(first));
 | 
			
		||||
                if (o.compare(first, second) === -1) return o.negate(o.subtract(second, first));
 | 
			
		||||
                var a = first.value, b = second.value;
 | 
			
		||||
                var result = [],
 | 
			
		||||
					borrow = 0;
 | 
			
		||||
                for (var i = 0; i < a.length; i++) {
 | 
			
		||||
                    var tmp = a[i] - borrow;
 | 
			
		||||
                    borrow = tmp < b[i] ? 1 : 0;
 | 
			
		||||
                    var minuend = (borrow * base) + tmp - b[i];
 | 
			
		||||
                    result.push(minuend);
 | 
			
		||||
                }
 | 
			
		||||
                return bigInt(result, sign.positive);
 | 
			
		||||
            },
 | 
			
		||||
            minus: function (n, m) {
 | 
			
		||||
                return o.subtract(n, m);
 | 
			
		||||
            },
 | 
			
		||||
            multiply: function (n, m) {
 | 
			
		||||
                var s, first = self, second;
 | 
			
		||||
                if (m) (first = parse(n)) && (second = parse(m));
 | 
			
		||||
                else second = parse(n, first);
 | 
			
		||||
                s = first.sign !== second.sign;
 | 
			
		||||
                var a = first.value, b = second.value;
 | 
			
		||||
                var resultSum = [];
 | 
			
		||||
                for (var i = 0; i < a.length; i++) {
 | 
			
		||||
                    resultSum[i] = [];
 | 
			
		||||
                    var j = i;
 | 
			
		||||
                    while (j--) {
 | 
			
		||||
                        resultSum[i].push(0);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                var carry = 0;
 | 
			
		||||
                for (var i = 0; i < a.length; i++) {
 | 
			
		||||
                    var x = a[i];
 | 
			
		||||
                    for (var j = 0; j < b.length || carry > 0; j++) {
 | 
			
		||||
                        var y = b[j];
 | 
			
		||||
                        var product = y ? (x * y) + carry : carry;
 | 
			
		||||
                        carry = product > base ? Math.floor(product / base) : 0;
 | 
			
		||||
                        product -= carry * base;
 | 
			
		||||
                        resultSum[i].push(product);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                var max = -1;
 | 
			
		||||
                for (var i = 0; i < resultSum.length; i++) {
 | 
			
		||||
                    var len = resultSum[i].length;
 | 
			
		||||
                    if (len > max) max = len;
 | 
			
		||||
                }
 | 
			
		||||
                var result = [], carry = 0;
 | 
			
		||||
                for (var i = 0; i < max || carry > 0; i++) {
 | 
			
		||||
                    var sum = carry;
 | 
			
		||||
                    for (var j = 0; j < resultSum.length; j++) {
 | 
			
		||||
                        sum += resultSum[j][i] || 0;
 | 
			
		||||
                    }
 | 
			
		||||
                    carry = sum > base ? Math.floor(sum / base) : 0;
 | 
			
		||||
                    sum -= carry * base;
 | 
			
		||||
                    result.push(sum);
 | 
			
		||||
                }
 | 
			
		||||
                return bigInt(result, s);
 | 
			
		||||
            },
 | 
			
		||||
            times: function (n, m) {
 | 
			
		||||
                return o.multiply(n, m);
 | 
			
		||||
            },
 | 
			
		||||
            divmod: function (n, m) {
 | 
			
		||||
                var s, first = self, second;
 | 
			
		||||
                if (m) (first = parse(n)) && (second = parse(m));
 | 
			
		||||
                else second = parse(n, first);
 | 
			
		||||
                s = first.sign !== second.sign;
 | 
			
		||||
                if (bigInt(first.value, first.sign).equals(0)) return {
 | 
			
		||||
                    quotient: bigInt([0], sign.positive),
 | 
			
		||||
                    remainder: bigInt([0], sign.positive)
 | 
			
		||||
                };
 | 
			
		||||
                if (second.equals(0)) throw new Error("Cannot divide by zero");
 | 
			
		||||
                var a = first.value, b = second.value;
 | 
			
		||||
                var result = [], remainder = [];
 | 
			
		||||
                for (var i = a.length - 1; i >= 0; i--) {
 | 
			
		||||
                    var n = [a[i]].concat(remainder);
 | 
			
		||||
                    var quotient = goesInto(b, n);
 | 
			
		||||
                    result.push(quotient.result);
 | 
			
		||||
                    remainder = quotient.remainder;
 | 
			
		||||
                }
 | 
			
		||||
                result.reverse();
 | 
			
		||||
                return {
 | 
			
		||||
                    quotient: bigInt(result, s),
 | 
			
		||||
                    remainder: bigInt(remainder, first.sign)
 | 
			
		||||
                };
 | 
			
		||||
            },
 | 
			
		||||
            divide: function (n, m) {
 | 
			
		||||
                return o.divmod(n, m).quotient;
 | 
			
		||||
            },
 | 
			
		||||
            over: function (n, m) {
 | 
			
		||||
                return o.divide(n, m);
 | 
			
		||||
            },
 | 
			
		||||
            mod: function (n, m) {
 | 
			
		||||
                return o.divmod(n, m).remainder;
 | 
			
		||||
            },
 | 
			
		||||
            pow: function (n, m) {
 | 
			
		||||
                var first = self, second;
 | 
			
		||||
                if (m) (first = parse(n)) && (second = parse(m));
 | 
			
		||||
                else second = parse(n, first);
 | 
			
		||||
                var a = first, b = second;
 | 
			
		||||
                if (b.lesser(0)) return ZERO;
 | 
			
		||||
                if (b.equals(0)) return ONE;
 | 
			
		||||
                var result = bigInt(a.value, a.sign);
 | 
			
		||||
 | 
			
		||||
                if (b.mod(2).equals(0)) {
 | 
			
		||||
                    var c = result.pow(b.over(2));
 | 
			
		||||
                    return c.times(c);
 | 
			
		||||
                } else {
 | 
			
		||||
                    return result.times(result.pow(b.minus(1)));
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            next: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                return o.add(first, 1);
 | 
			
		||||
            },
 | 
			
		||||
            prev: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                return o.subtract(first, 1);
 | 
			
		||||
            },
 | 
			
		||||
            compare: function (n, m) {
 | 
			
		||||
                var first = self, second;
 | 
			
		||||
                if (m) (first = parse(n)) && (second = parse(m, first));
 | 
			
		||||
                else second = parse(n, first);
 | 
			
		||||
                normalize(first, second);
 | 
			
		||||
                if (first.value.length === 1 && second.value.length === 1 && first.value[0] === 0 && second.value[0] === 0) return 0;
 | 
			
		||||
                if (second.sign !== first.sign) return first.sign === sign.positive ? 1 : -1;
 | 
			
		||||
                var multiplier = first.sign === sign.positive ? 1 : -1;
 | 
			
		||||
                var a = first.value, b = second.value;
 | 
			
		||||
                for (var i = a.length - 1; i >= 0; i--) {
 | 
			
		||||
                    if (a[i] > b[i]) return 1 * multiplier;
 | 
			
		||||
                    if (b[i] > a[i]) return -1 * multiplier;
 | 
			
		||||
                }
 | 
			
		||||
                return 0;
 | 
			
		||||
            },
 | 
			
		||||
            compareAbs: function (n, m) {
 | 
			
		||||
                var first = self, second;
 | 
			
		||||
                if (m) (first = parse(n)) && (second = parse(m, first));
 | 
			
		||||
                else second = parse(n, first);
 | 
			
		||||
                first.sign = second.sign = sign.positive;
 | 
			
		||||
                return o.compare(first, second);
 | 
			
		||||
            },
 | 
			
		||||
            equals: function (n, m) {
 | 
			
		||||
                return o.compare(n, m) === 0;
 | 
			
		||||
            },
 | 
			
		||||
            notEquals: function (n, m) {
 | 
			
		||||
                return !o.equals(n, m);
 | 
			
		||||
            },
 | 
			
		||||
            lesser: function (n, m) {
 | 
			
		||||
                return o.compare(n, m) < 0;
 | 
			
		||||
            },
 | 
			
		||||
            greater: function (n, m) {
 | 
			
		||||
                return o.compare(n, m) > 0;
 | 
			
		||||
            },
 | 
			
		||||
            greaterOrEquals: function (n, m) {
 | 
			
		||||
                return o.compare(n, m) >= 0;
 | 
			
		||||
            },
 | 
			
		||||
            lesserOrEquals: function (n, m) {
 | 
			
		||||
                return o.compare(n, m) <= 0;
 | 
			
		||||
            },
 | 
			
		||||
            isPositive: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                return first.sign === sign.positive;
 | 
			
		||||
            },
 | 
			
		||||
            isNegative: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                return first.sign === sign.negative;
 | 
			
		||||
            },
 | 
			
		||||
            isEven: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                return first.value[0] % 2 === 0;
 | 
			
		||||
            },
 | 
			
		||||
            isOdd: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                return first.value[0] % 2 === 1;
 | 
			
		||||
            },
 | 
			
		||||
            toString: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                var str = "", len = first.value.length;
 | 
			
		||||
                while (len--) {
 | 
			
		||||
                    if (first.value[len].toString().length === 8) str += first.value[len];
 | 
			
		||||
                    else str += (base.toString() + first.value[len]).slice(-logBase);
 | 
			
		||||
                }
 | 
			
		||||
                while (str[0] === "0") {
 | 
			
		||||
                    str = str.slice(1);
 | 
			
		||||
                }
 | 
			
		||||
                if (!str.length) str = "0";
 | 
			
		||||
                var s = (first.sign === sign.positive || str == "0") ? "" : "-";
 | 
			
		||||
                return s + str;
 | 
			
		||||
            },
 | 
			
		||||
            toHex: function (m) {
 | 
			
		||||
                var first = m || self;
 | 
			
		||||
                var str = "";
 | 
			
		||||
				var l = this.abs();
 | 
			
		||||
                while (l > 0) {
 | 
			
		||||
					var qr = l.divmod(256);
 | 
			
		||||
					var b = qr.remainder.toJSNumber();
 | 
			
		||||
					str = (b >> 4).toString(16) + (b & 15).toString(16) + str;
 | 
			
		||||
                    l = qr.quotient;
 | 
			
		||||
                }
 | 
			
		||||
                return (this.isNegative() ? "-" : "") + "0x" + str;
 | 
			
		||||
            },
 | 
			
		||||
            toJSNumber: function (m) {
 | 
			
		||||
                return +o.toString(m);
 | 
			
		||||
            },
 | 
			
		||||
            valueOf: function (m) {
 | 
			
		||||
                return o.toJSNumber(m);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        return o;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var ZERO = bigInt([0], sign.positive);
 | 
			
		||||
    var ONE = bigInt([1], sign.positive);
 | 
			
		||||
    var MINUS_ONE = bigInt([1], sign.negative);
 | 
			
		||||
 | 
			
		||||
    var fnReturn = function (a) {
 | 
			
		||||
        if (typeof a === "undefined") return ZERO;
 | 
			
		||||
        return parse(a);
 | 
			
		||||
    };
 | 
			
		||||
    fnReturn.zero = ZERO;
 | 
			
		||||
    fnReturn.one = ONE;
 | 
			
		||||
    fnReturn.minusOne = MINUS_ONE;
 | 
			
		||||
    return fnReturn;
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
if (typeof module !== "undefined") {
 | 
			
		||||
    module.exports = bigInt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										145
									
								
								ethereal/assets/ext/ethereum.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,145 @@
 | 
			
		||||
// Main Ethereum library
 | 
			
		||||
window.eth = {
 | 
			
		||||
	prototype: Object(),
 | 
			
		||||
 | 
			
		||||
	// Retrieve block
 | 
			
		||||
	//
 | 
			
		||||
	// Either supply a number or a string. Type is determent for the lookup method
 | 
			
		||||
	// string - Retrieves the block by looking up the hash
 | 
			
		||||
	// number - Retrieves the block by looking up the block number
 | 
			
		||||
        getBlock: function(numberOrHash, cb) {
 | 
			
		||||
                var func;
 | 
			
		||||
                if(typeof numberOrHash == "string") {
 | 
			
		||||
                        func =  "getBlockByHash";
 | 
			
		||||
                } else {
 | 
			
		||||
                        func =  "getBlockByNumber";
 | 
			
		||||
                }
 | 
			
		||||
                postData({call: func, args: [numberOrHash]}, cb);
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
	// Create transaction
 | 
			
		||||
	//
 | 
			
		||||
	// Transact between two state objects
 | 
			
		||||
	transact: function(sec, recipient, value, gas, gasPrice, data, cb) {
 | 
			
		||||
		postData({call: "transact", args: [sec, recipient, value, gas, gasPrice, data]}, cb);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	create: function(sec, value, gas, gasPrice, init, body, cb) {
 | 
			
		||||
		postData({call: "create", args: [sec, value, gas, gasPrice, init, body]}, cb);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getStorageAt: function(address, storageAddress, cb) {
 | 
			
		||||
		postData({call: "getStorage", args: [address, storageAddress]}, cb);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getStateKeyVals: function(address, cb){
 | 
			
		||||
		postData({call: "getStateKeyVals", args: [address]}, cb);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getKey: function(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) {
 | 
			
		||||
		postData({call: "getBalance", args: [address]}, cb);
 | 
			
		||||
	},
 | 
			
		||||
	getTransactionsFor: function(address, cb) {
 | 
			
		||||
		postData({call: "getTransactionsFor", args: [address]}, cb);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getSecretToAddress: function(sec, cb) {
 | 
			
		||||
		postData({call: "getSecretToAddress", args: [sec]}, cb);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	watch: function(address, storageAddrOrCb, cb) {
 | 
			
		||||
		var ev;
 | 
			
		||||
		if(cb === undefined) {
 | 
			
		||||
			cb = storageAddrOrCb;
 | 
			
		||||
			storageAddrOrCb = "";
 | 
			
		||||
			ev = "object:"+address;
 | 
			
		||||
		} else {
 | 
			
		||||
			ev = "storage:"+address+":"+storageAddrOrCb;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		eth.on(ev, cb)
 | 
			
		||||
 | 
			
		||||
		postData({call: "watch", args: [address, storageAddrOrCb]});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	disconnect: function(address, storageAddrOrCb, cb) {
 | 
			
		||||
		var ev;
 | 
			
		||||
		if(cb === undefined) {
 | 
			
		||||
			cb = storageAddrOrCb;
 | 
			
		||||
			storageAddrOrCb = "";
 | 
			
		||||
			ev = "object:"+address;
 | 
			
		||||
		} else {
 | 
			
		||||
			ev = "storage:"+address+":"+storageAddrOrCb;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		eth.off(ev, cb)
 | 
			
		||||
 | 
			
		||||
		postData({call: "disconnect", args: [address, storageAddrOrCb]});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	set: function(props) {
 | 
			
		||||
		postData({call: "set", args: props});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	on: function(event, cb) {
 | 
			
		||||
		if(eth._onCallbacks[event] === undefined) {
 | 
			
		||||
			eth._onCallbacks[event] = [];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		eth._onCallbacks[event].push(cb);
 | 
			
		||||
 | 
			
		||||
		return this
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	off: function(event, cb) {
 | 
			
		||||
		if(eth._onCallbacks[event] !== undefined) {
 | 
			
		||||
			var callbacks = eth._onCallbacks[event];
 | 
			
		||||
			for(var i = 0; i < callbacks.length; i++) {
 | 
			
		||||
				if(callbacks[i] === cb) {
 | 
			
		||||
					delete callbacks[i];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return this
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	trigger: function(event, data) {
 | 
			
		||||
		var callbacks = eth._onCallbacks[event];
 | 
			
		||||
		if(callbacks !== undefined) {
 | 
			
		||||
			for(var i = 0; i < callbacks.length; i++) {
 | 
			
		||||
				// Figure out whether the returned data was an array
 | 
			
		||||
				// array means multiple return arguments (multiple params)
 | 
			
		||||
				if(data instanceof Array) {
 | 
			
		||||
					callbacks[i].apply(this, data);
 | 
			
		||||
				} else {
 | 
			
		||||
					callbacks[i].call(this, data);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
window.eth._callbacks = {}
 | 
			
		||||
window.eth._onCallbacks = {}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								ethereal/assets/ext/pre.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,58 @@
 | 
			
		||||
function debug(/**/) {
 | 
			
		||||
	var args = arguments;
 | 
			
		||||
	var msg = ""
 | 
			
		||||
	for(var i = 0; i < args.length; i++){
 | 
			
		||||
		if(typeof args[i] === "object") {
 | 
			
		||||
			msg += " " + JSON.stringify(args[i])
 | 
			
		||||
		} else {
 | 
			
		||||
			msg += " " + args[i]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	postData({call:"debug", args:[msg]})
 | 
			
		||||
	document.getElementById("debug").innerHTML += "<br>" + msg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper function for generating pseudo callbacks and sending data to the QML part of the application
 | 
			
		||||
function postData(data, cb) {
 | 
			
		||||
	data._seed = Math.floor(Math.random() * 1000000)
 | 
			
		||||
	if(cb) {
 | 
			
		||||
		eth._callbacks[data._seed] = cb;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(data.args === undefined) {
 | 
			
		||||
		data.args = [];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	navigator.qt.postMessage(JSON.stringify(data));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
navigator.qt.onmessage = function(ev) {
 | 
			
		||||
	var data = JSON.parse(ev.data)
 | 
			
		||||
 | 
			
		||||
	if(data._event !== undefined) {
 | 
			
		||||
		eth.trigger(data._event, data.data);
 | 
			
		||||
	} else {
 | 
			
		||||
		if(data._seed) {
 | 
			
		||||
			var cb = eth._callbacks[data._seed];
 | 
			
		||||
			if(cb) {
 | 
			
		||||
				// Figure out whether the returned data was an array
 | 
			
		||||
				// array means multiple return arguments (multiple params)
 | 
			
		||||
				if(data.data instanceof Array) {
 | 
			
		||||
					cb.apply(this, data.data)
 | 
			
		||||
				} else {
 | 
			
		||||
					cb.call(this, data.data)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Remove the "trigger" callback
 | 
			
		||||
				delete eth._callbacks[ev._seed];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
window.onerror = function(message, file, lineNumber, column, errorObj) {
 | 
			
		||||
	debug(file, message, lineNumber+":"+column, errorObj);
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								ethereal/assets/ext/string.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,58 @@
 | 
			
		||||
String.prototype.pad = function(l, r) {
 | 
			
		||||
	if (r === undefined) {
 | 
			
		||||
		r = l
 | 
			
		||||
		if (!(this.substr(0, 2) == "0x" || /^\d+$/.test(this)))
 | 
			
		||||
			l = 0
 | 
			
		||||
	}
 | 
			
		||||
	var ret = this.bin();
 | 
			
		||||
	while (ret.length < l)
 | 
			
		||||
		ret = "\0" + ret
 | 
			
		||||
	while (ret.length < r)
 | 
			
		||||
		ret = ret + "\0"
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String.prototype.unpad = function() {
 | 
			
		||||
	var i = this.length;
 | 
			
		||||
	while (i && this[i - 1] == "\0")
 | 
			
		||||
		--i
 | 
			
		||||
	return this.substr(0, i)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String.prototype.bin = function() {
 | 
			
		||||
	if (this.substr(0, 2) == "0x") {
 | 
			
		||||
		bytes = []
 | 
			
		||||
		var i = 2;
 | 
			
		||||
 | 
			
		||||
		// Check if it's odd - pad with a zero if so.
 | 
			
		||||
		if (this.length % 2)
 | 
			
		||||
			bytes.push(parseInt(this.substr(i++, 1), 16))
 | 
			
		||||
 | 
			
		||||
		for (; i < this.length - 1; i += 2)
 | 
			
		||||
			bytes.push(parseInt(this.substr(i, 2), 16));
 | 
			
		||||
 | 
			
		||||
		return String.fromCharCode.apply(String, bytes);
 | 
			
		||||
	} else if (/^\d+$/.test(this))
 | 
			
		||||
		return bigInt(this.substr(0)).toHex().bin()
 | 
			
		||||
 | 
			
		||||
	// Otherwise we'll return the "String" object instead of an actual string
 | 
			
		||||
	return this.substr(0, this.length)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String.prototype.unbin = function() {
 | 
			
		||||
	var i, l, o = '';
 | 
			
		||||
	for(i = 0, l = this.length; i < l; i++) {
 | 
			
		||||
		var n = this.charCodeAt(i).toString(16);
 | 
			
		||||
		o += n.length < 2 ? '0' + n : n;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "0x" + o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String.prototype.dec = function() {
 | 
			
		||||
	return bigInt(this.substr(0)).toString()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String.prototype.hex = function() {
 | 
			
		||||
	return bigInt(this.substr(0)).toHex()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								ethereal/assets/facet.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 27 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								ethereal/assets/heart.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.2 KiB  | 
							
								
								
									
										272
									
								
								ethereal/assets/muted/codemirror.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,272 @@
 | 
			
		||||
/* BASICS */
 | 
			
		||||
 | 
			
		||||
.CodeMirror {
 | 
			
		||||
  /* Set height, width, borders, and global font properties here */
 | 
			
		||||
  font-family: monospace;
 | 
			
		||||
  height: 300px;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-scroll {
 | 
			
		||||
  /* Set scrolling behaviour here */
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* PADDING */
 | 
			
		||||
 | 
			
		||||
.CodeMirror-lines {
 | 
			
		||||
  padding: 4px 0; /* Vertical padding around content */
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror pre {
 | 
			
		||||
  padding: 0 4px; /* Horizontal padding of content */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
 | 
			
		||||
  background-color: white; /* The little square between H and V scrollbars */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* GUTTER */
 | 
			
		||||
 | 
			
		||||
.CodeMirror-gutters {
 | 
			
		||||
  border-right: 1px solid #ddd;
 | 
			
		||||
  background-color: #f7f7f7;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-linenumbers {}
 | 
			
		||||
.CodeMirror-linenumber {
 | 
			
		||||
  padding: 0 3px 0 5px;
 | 
			
		||||
  min-width: 20px;
 | 
			
		||||
  text-align: right;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  -moz-box-sizing: content-box;
 | 
			
		||||
  box-sizing: content-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* CURSOR */
 | 
			
		||||
 | 
			
		||||
.CodeMirror div.CodeMirror-cursor {
 | 
			
		||||
  border-left: 1px solid black;
 | 
			
		||||
}
 | 
			
		||||
/* Shown when moving in bi-directional text */
 | 
			
		||||
.CodeMirror div.CodeMirror-secondarycursor {
 | 
			
		||||
  border-left: 1px solid silver;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
 | 
			
		||||
  width: auto;
 | 
			
		||||
  border: 0;
 | 
			
		||||
  background: #7e7;
 | 
			
		||||
}
 | 
			
		||||
/* Can style cursor different in overwrite (non-insert) mode */
 | 
			
		||||
div.CodeMirror-overwrite div.CodeMirror-cursor {}
 | 
			
		||||
 | 
			
		||||
.cm-tab { display: inline-block; }
 | 
			
		||||
 | 
			
		||||
.CodeMirror-ruler {
 | 
			
		||||
  border-left: 1px solid #ccc;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* DEFAULT THEME */
 | 
			
		||||
 | 
			
		||||
.cm-s-default .cm-keyword {color: #708;}
 | 
			
		||||
.cm-s-default .cm-atom {color: #219;}
 | 
			
		||||
.cm-s-default .cm-number {color: #164;}
 | 
			
		||||
.cm-s-default .cm-def {color: #00f;}
 | 
			
		||||
.cm-s-default .cm-variable,
 | 
			
		||||
.cm-s-default .cm-punctuation,
 | 
			
		||||
.cm-s-default .cm-property,
 | 
			
		||||
.cm-s-default .cm-operator {}
 | 
			
		||||
.cm-s-default .cm-variable-2 {color: #05a;}
 | 
			
		||||
.cm-s-default .cm-variable-3 {color: #085;}
 | 
			
		||||
.cm-s-default .cm-comment {color: #a50;}
 | 
			
		||||
.cm-s-default .cm-string {color: #a11;}
 | 
			
		||||
.cm-s-default .cm-string-2 {color: #f50;}
 | 
			
		||||
.cm-s-default .cm-meta {color: #555;}
 | 
			
		||||
.cm-s-default .cm-qualifier {color: #555;}
 | 
			
		||||
.cm-s-default .cm-builtin {color: #30a;}
 | 
			
		||||
.cm-s-default .cm-bracket {color: #997;}
 | 
			
		||||
.cm-s-default .cm-tag {color: #170;}
 | 
			
		||||
.cm-s-default .cm-attribute {color: #00c;}
 | 
			
		||||
.cm-s-default .cm-header {color: blue;}
 | 
			
		||||
.cm-s-default .cm-quote {color: #090;}
 | 
			
		||||
.cm-s-default .cm-hr {color: #999;}
 | 
			
		||||
.cm-s-default .cm-link {color: #00c;}
 | 
			
		||||
 | 
			
		||||
.cm-negative {color: #d44;}
 | 
			
		||||
.cm-positive {color: #292;}
 | 
			
		||||
.cm-header, .cm-strong {font-weight: bold;}
 | 
			
		||||
.cm-em {font-style: italic;}
 | 
			
		||||
.cm-link {text-decoration: underline;}
 | 
			
		||||
 | 
			
		||||
.cm-s-default .cm-error {color: #f00;}
 | 
			
		||||
.cm-invalidchar {color: #f00;}
 | 
			
		||||
 | 
			
		||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
 | 
			
		||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 | 
			
		||||
.CodeMirror-activeline-background {background: #e8f2ff;}
 | 
			
		||||
 | 
			
		||||
/* STOP */
 | 
			
		||||
 | 
			
		||||
/* The rest of this file contains styles related to the mechanics of
 | 
			
		||||
   the editor. You probably shouldn't touch them. */
 | 
			
		||||
 | 
			
		||||
.CodeMirror {
 | 
			
		||||
  line-height: 1;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  background: white;
 | 
			
		||||
  color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-scroll {
 | 
			
		||||
  /* 30px is the magic margin used to hide the element's real scrollbars */
 | 
			
		||||
  /* See overflow: hidden in .CodeMirror */
 | 
			
		||||
  margin-bottom: -30px; margin-right: -30px;
 | 
			
		||||
  padding-bottom: 30px;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  outline: none; /* Prevent dragging from highlighting the element */
 | 
			
		||||
  position: relative;
 | 
			
		||||
  -moz-box-sizing: content-box;
 | 
			
		||||
  box-sizing: content-box;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-sizer {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  border-right: 30px solid transparent;
 | 
			
		||||
  -moz-box-sizing: content-box;
 | 
			
		||||
  box-sizing: content-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
 | 
			
		||||
   before actuall scrolling happens, thus preventing shaking and
 | 
			
		||||
   flickering artifacts. */
 | 
			
		||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 6;
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-vscrollbar {
 | 
			
		||||
  right: 0; top: 0;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-hscrollbar {
 | 
			
		||||
  bottom: 0; left: 0;
 | 
			
		||||
  overflow-y: hidden;
 | 
			
		||||
  overflow-x: scroll;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-scrollbar-filler {
 | 
			
		||||
  right: 0; bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-gutter-filler {
 | 
			
		||||
  left: 0; bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-gutters {
 | 
			
		||||
  position: absolute; left: 0; top: 0;
 | 
			
		||||
  padding-bottom: 30px;
 | 
			
		||||
  z-index: 3;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-gutter {
 | 
			
		||||
  white-space: normal;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  -moz-box-sizing: content-box;
 | 
			
		||||
  box-sizing: content-box;
 | 
			
		||||
  padding-bottom: 30px;
 | 
			
		||||
  margin-bottom: -32px;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  /* Hack to make IE7 behave */
 | 
			
		||||
  *zoom:1;
 | 
			
		||||
  *display:inline;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-gutter-elt {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  cursor: default;
 | 
			
		||||
  z-index: 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-lines {
 | 
			
		||||
  cursor: text;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror pre {
 | 
			
		||||
  /* Reset some styles that the rest of the page might have set */
 | 
			
		||||
  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
 | 
			
		||||
  border-width: 0;
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  font-family: inherit;
 | 
			
		||||
  font-size: inherit;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  white-space: pre;
 | 
			
		||||
  word-wrap: normal;
 | 
			
		||||
  line-height: inherit;
 | 
			
		||||
  color: inherit;
 | 
			
		||||
  z-index: 2;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-wrap pre {
 | 
			
		||||
  word-wrap: break-word;
 | 
			
		||||
  white-space: pre-wrap;
 | 
			
		||||
  word-break: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-linebackground {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 0; right: 0; top: 0; bottom: 0;
 | 
			
		||||
  z-index: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-linewidget {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  z-index: 2;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-widget {}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-wrap .CodeMirror-scroll {
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-measure {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-measure pre { position: static; }
 | 
			
		||||
 | 
			
		||||
.CodeMirror div.CodeMirror-cursor {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  border-right: none;
 | 
			
		||||
  width: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.CodeMirror-cursors {
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
.CodeMirror-focused div.CodeMirror-cursors {
 | 
			
		||||
  visibility: visible;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.CodeMirror-selected { background: #d9d9d9; }
 | 
			
		||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
 | 
			
		||||
.CodeMirror-crosshair { cursor: crosshair; }
 | 
			
		||||
 | 
			
		||||
.cm-searching {
 | 
			
		||||
  background: #ffa;
 | 
			
		||||
  background: rgba(255, 255, 0, .4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
 | 
			
		||||
.CodeMirror span { *vertical-align: text-bottom; }
 | 
			
		||||
 | 
			
		||||
/* Used to force a border model for a node */
 | 
			
		||||
.cm-force-border { padding-right: .1px; }
 | 
			
		||||
 | 
			
		||||
@media print {
 | 
			
		||||
  /* Hide the cursor when printing */
 | 
			
		||||
  .CodeMirror div.CodeMirror-cursors {
 | 
			
		||||
    visibility: hidden;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								ethereal/assets/muted/debugger.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,53 @@
 | 
			
		||||
<!doctype>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<style type="text/css">
 | 
			
		||||
    html, body {
 | 
			
		||||
        margin: 0; padding: 0;
 | 
			
		||||
        min-height: 100%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #debugger {
 | 
			
		||||
	    height: 100%;
 | 
			
		||||
	    font-family: "Monaco"
 | 
			
		||||
    }
 | 
			
		||||
    #debugger .line {
 | 
			
		||||
	    overflow: none;
 | 
			
		||||
    }
 | 
			
		||||
    #debugger .col1, #debugger .col2 {
 | 
			
		||||
	    float: left;
 | 
			
		||||
	    padding: 3px;
 | 
			
		||||
    }
 | 
			
		||||
    #debugger .col1 {
 | 
			
		||||
	    width: 10px;
 | 
			
		||||
	    padding-left: 10px
 | 
			
		||||
	    -webkit-touch-callout: none;
 | 
			
		||||
	    -webkit-user-select: none;
 | 
			
		||||
	    -khtml-user-select: none;
 | 
			
		||||
	    -moz-user-select: none;
 | 
			
		||||
	    -ms-user-select: none;
 | 
			
		||||
	    user-select: none;
 | 
			
		||||
    }
 | 
			
		||||
    #debugger .col2 {
 | 
			
		||||
	    width: 90%;
 | 
			
		||||
    }
 | 
			
		||||
    .prompt {
 | 
			
		||||
	    color: "#5089D4";
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
<div id="debugger">
 | 
			
		||||
	<div class="line">
 | 
			
		||||
		<div class="col1 prompt">
 | 
			
		||||
			>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="col2" contenteditable>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										23
									
								
								ethereal/assets/muted/eclipse.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,23 @@
 | 
			
		||||
.cm-s-eclipse span.cm-meta {color: #FF1717;}
 | 
			
		||||
.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }
 | 
			
		||||
.cm-s-eclipse span.cm-atom {color: #219;}
 | 
			
		||||
.cm-s-eclipse span.cm-number {color: #164;}
 | 
			
		||||
.cm-s-eclipse span.cm-def {color: #00f;}
 | 
			
		||||
.cm-s-eclipse span.cm-variable {color: black;}
 | 
			
		||||
.cm-s-eclipse span.cm-variable-2 {color: #0000C0;}
 | 
			
		||||
.cm-s-eclipse span.cm-variable-3 {color: #0000C0;}
 | 
			
		||||
.cm-s-eclipse span.cm-property {color: black;}
 | 
			
		||||
.cm-s-eclipse span.cm-operator {color: black;}
 | 
			
		||||
.cm-s-eclipse span.cm-comment {color: #3F7F5F;}
 | 
			
		||||
.cm-s-eclipse span.cm-string {color: #2A00FF;}
 | 
			
		||||
.cm-s-eclipse span.cm-string-2 {color: #f50;}
 | 
			
		||||
.cm-s-eclipse span.cm-qualifier {color: #555;}
 | 
			
		||||
.cm-s-eclipse span.cm-builtin {color: #30a;}
 | 
			
		||||
.cm-s-eclipse span.cm-bracket {color: #cc7;}
 | 
			
		||||
.cm-s-eclipse span.cm-tag {color: #170;}
 | 
			
		||||
.cm-s-eclipse span.cm-attribute {color: #00c;}
 | 
			
		||||
.cm-s-eclipse span.cm-link {color: #219;}
 | 
			
		||||
.cm-s-eclipse span.cm-error {color: #f00;}
 | 
			
		||||
 | 
			
		||||
.cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;}
 | 
			
		||||
.cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
 | 
			
		||||
							
								
								
									
										80
									
								
								ethereal/assets/muted/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,80 @@
 | 
			
		||||
<!doctype>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<title>Mutan Editor</title>
 | 
			
		||||
<link rel="stylesheet" href="codemirror.css">
 | 
			
		||||
<link rel="stylesheet" href="eclipse.css">
 | 
			
		||||
<script src="lib/codemirror.js"></script>
 | 
			
		||||
<script src="lib/matchbrackets.js"></script>
 | 
			
		||||
<script src="lib/go.js"></script>
 | 
			
		||||
<script src="muted.js"></script>
 | 
			
		||||
 | 
			
		||||
<style type="text/css">
 | 
			
		||||
    html, body {
 | 
			
		||||
        margin: 0; padding: 0;
 | 
			
		||||
        min-height: 100%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #debugger {
 | 
			
		||||
	    height: 30%;
 | 
			
		||||
	    font-family: "Monaco";
 | 
			
		||||
        border-top: 5px solid grey;
 | 
			
		||||
    }
 | 
			
		||||
    #debugger .line {
 | 
			
		||||
	    overflow: none;
 | 
			
		||||
    }
 | 
			
		||||
    #debugger .col1, #debugger .col2 {
 | 
			
		||||
	    float: left;
 | 
			
		||||
	    padding: 3px;
 | 
			
		||||
    }
 | 
			
		||||
    #debugger .col1 {
 | 
			
		||||
	    width: 10px;
 | 
			
		||||
	    padding-left: 10px
 | 
			
		||||
	    -webkit-touch-callout: none;
 | 
			
		||||
	    -webkit-user-select: none;
 | 
			
		||||
	    -khtml-user-select: none;
 | 
			
		||||
	    -moz-user-select: none;
 | 
			
		||||
	    -ms-user-select: none;
 | 
			
		||||
	    user-select: none;
 | 
			
		||||
    }
 | 
			
		||||
    #debugger .col2 {
 | 
			
		||||
	    width: 90%;
 | 
			
		||||
    }
 | 
			
		||||
    .prompt {
 | 
			
		||||
	    color: "#5089D4";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .CodeMirror {
 | 
			
		||||
        height: 70%;
 | 
			
		||||
	font-size: 14pt;
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
<textarea id="editor"></textarea>
 | 
			
		||||
 | 
			
		||||
<div id="debugger">
 | 
			
		||||
	<div class="line">
 | 
			
		||||
		<div class="col1 prompt">
 | 
			
		||||
			>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="col2" contenteditable>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    var textArea = document.querySelector("#editor")
 | 
			
		||||
    var editor = CodeMirror.fromTextArea(textArea, {
 | 
			
		||||
        theme: "eclipse",
 | 
			
		||||
        mode: "text/html",
 | 
			
		||||
        lineNumbers: true,
 | 
			
		||||
        mode: "text/x-go",
 | 
			
		||||
        indentUnit: 8,
 | 
			
		||||
        tabSize: 8,
 | 
			
		||||
        indentWithTabs: true,
 | 
			
		||||
    });
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										7526
									
								
								ethereal/assets/muted/lib/codemirror.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										182
									
								
								ethereal/assets/muted/lib/go.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,182 @@
 | 
			
		||||
(function(mod) {
 | 
			
		||||
  if (typeof exports == "object" && typeof module == "object") // CommonJS
 | 
			
		||||
    mod(require("../../lib/codemirror"));
 | 
			
		||||
  else if (typeof define == "function" && define.amd) // AMD
 | 
			
		||||
    define(["../../lib/codemirror"], mod);
 | 
			
		||||
  else // Plain browser env
 | 
			
		||||
    mod(CodeMirror);
 | 
			
		||||
})(function(CodeMirror) {
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
CodeMirror.defineMode("go", function(config) {
 | 
			
		||||
  var indentUnit = config.indentUnit;
 | 
			
		||||
 | 
			
		||||
  var keywords = {
 | 
			
		||||
    "break":true, "case":true, "chan":true, "const":true, "continue":true,
 | 
			
		||||
    "default":true, "defer":true, "else":true, "fallthrough":true, "for":true,
 | 
			
		||||
    "func":true, "go":true, "goto":true, "if":true, "import":true,
 | 
			
		||||
    "interface":true, "map":true, "package":true, "range":true, "return":true,
 | 
			
		||||
    "select":true, "struct":true, "switch":true, "type":true, "var":true,
 | 
			
		||||
    "bool":true, "byte":true, "complex64":true, "complex128":true,
 | 
			
		||||
    "float32":true, "float64":true, "int8":true, "int16":true, "int32":true,
 | 
			
		||||
    "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true,
 | 
			
		||||
    "uint64":true, "int":true, "uint":true, "uintptr":true, "big": true,
 | 
			
		||||
    "main": true, "init": true, "this":true
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  var atoms = {
 | 
			
		||||
    "true":true, "false":true, "iota":true, "nil":true, "append":true,
 | 
			
		||||
    "cap":true, "close":true, "complex":true, "copy":true, "imag":true,
 | 
			
		||||
    "len":true, "make":true, "new":true, "panic":true, "print":true,
 | 
			
		||||
    "println":true, "real":true, "recover":true, 
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  var isOperatorChar = /[+\-*&^%:=<>!|\/]/;
 | 
			
		||||
 | 
			
		||||
  var curPunc;
 | 
			
		||||
 | 
			
		||||
  function tokenBase(stream, state) {
 | 
			
		||||
    var ch = stream.next();
 | 
			
		||||
    if (ch == '"' || ch == "'" || ch == "`") {
 | 
			
		||||
      state.tokenize = tokenString(ch);
 | 
			
		||||
      return state.tokenize(stream, state);
 | 
			
		||||
    }
 | 
			
		||||
    if (/[\d\.]/.test(ch)) {
 | 
			
		||||
      if (ch == ".") {
 | 
			
		||||
        stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
 | 
			
		||||
      } else if (ch == "0") {
 | 
			
		||||
        stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
 | 
			
		||||
      } else {
 | 
			
		||||
        stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
 | 
			
		||||
      }
 | 
			
		||||
      return "number";
 | 
			
		||||
    }
 | 
			
		||||
    if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
 | 
			
		||||
      curPunc = ch;
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
    if (ch == "/") {
 | 
			
		||||
      if (stream.eat("*")) {
 | 
			
		||||
        state.tokenize = tokenComment;
 | 
			
		||||
        return tokenComment(stream, state);
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.eat("/")) {
 | 
			
		||||
        stream.skipToEnd();
 | 
			
		||||
        return "comment";
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (isOperatorChar.test(ch)) {
 | 
			
		||||
      stream.eatWhile(isOperatorChar);
 | 
			
		||||
      return "operator";
 | 
			
		||||
    }
 | 
			
		||||
    stream.eatWhile(/[\w\$_]/);
 | 
			
		||||
    var cur = stream.current();
 | 
			
		||||
    if (keywords.propertyIsEnumerable(cur)) {
 | 
			
		||||
      if (cur == "case" || cur == "default") curPunc = "case";
 | 
			
		||||
      return "keyword";
 | 
			
		||||
    }
 | 
			
		||||
    if (atoms.propertyIsEnumerable(cur)) return "atom";
 | 
			
		||||
    return "variable";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function tokenString(quote) {
 | 
			
		||||
    return function(stream, state) {
 | 
			
		||||
      var escaped = false, next, end = false;
 | 
			
		||||
      while ((next = stream.next()) != null) {
 | 
			
		||||
        if (next == quote && !escaped) {end = true; break;}
 | 
			
		||||
        escaped = !escaped && next == "\\";
 | 
			
		||||
      }
 | 
			
		||||
      if (end || !(escaped || quote == "`"))
 | 
			
		||||
        state.tokenize = tokenBase;
 | 
			
		||||
      return "string";
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function tokenComment(stream, state) {
 | 
			
		||||
    var maybeEnd = false, ch;
 | 
			
		||||
    while (ch = stream.next()) {
 | 
			
		||||
      if (ch == "/" && maybeEnd) {
 | 
			
		||||
        state.tokenize = tokenBase;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      maybeEnd = (ch == "*");
 | 
			
		||||
    }
 | 
			
		||||
    return "comment";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function Context(indented, column, type, align, prev) {
 | 
			
		||||
    this.indented = indented;
 | 
			
		||||
    this.column = column;
 | 
			
		||||
    this.type = type;
 | 
			
		||||
    this.align = align;
 | 
			
		||||
    this.prev = prev;
 | 
			
		||||
  }
 | 
			
		||||
  function pushContext(state, col, type) {
 | 
			
		||||
    return state.context = new Context(state.indented, col, type, null, state.context);
 | 
			
		||||
  }
 | 
			
		||||
  function popContext(state) {
 | 
			
		||||
    var t = state.context.type;
 | 
			
		||||
    if (t == ")" || t == "]" || t == "}")
 | 
			
		||||
      state.indented = state.context.indented;
 | 
			
		||||
    return state.context = state.context.prev;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Interface
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    startState: function(basecolumn) {
 | 
			
		||||
      return {
 | 
			
		||||
        tokenize: null,
 | 
			
		||||
        context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
 | 
			
		||||
        indented: 0,
 | 
			
		||||
        startOfLine: true
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    token: function(stream, state) {
 | 
			
		||||
      var ctx = state.context;
 | 
			
		||||
      if (stream.sol()) {
 | 
			
		||||
        if (ctx.align == null) ctx.align = false;
 | 
			
		||||
        state.indented = stream.indentation();
 | 
			
		||||
        state.startOfLine = true;
 | 
			
		||||
        if (ctx.type == "case") ctx.type = "}";
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.eatSpace()) return null;
 | 
			
		||||
      curPunc = null;
 | 
			
		||||
      var style = (state.tokenize || tokenBase)(stream, state);
 | 
			
		||||
      if (style == "comment") return style;
 | 
			
		||||
      if (ctx.align == null) ctx.align = true;
 | 
			
		||||
 | 
			
		||||
      if (curPunc == "{") pushContext(state, stream.column(), "}");
 | 
			
		||||
      else if (curPunc == "[") pushContext(state, stream.column(), "]");
 | 
			
		||||
      else if (curPunc == "(") pushContext(state, stream.column(), ")");
 | 
			
		||||
      else if (curPunc == "case") ctx.type = "case";
 | 
			
		||||
      else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state);
 | 
			
		||||
      else if (curPunc == ctx.type) popContext(state);
 | 
			
		||||
      state.startOfLine = false;
 | 
			
		||||
      return style;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    indent: function(state, textAfter) {
 | 
			
		||||
      if (state.tokenize != tokenBase && state.tokenize != null) return 0;
 | 
			
		||||
      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
 | 
			
		||||
      if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) {
 | 
			
		||||
        state.context.type = "}";
 | 
			
		||||
        return ctx.indented;
 | 
			
		||||
      }
 | 
			
		||||
      var closing = firstChar == ctx.type;
 | 
			
		||||
      if (ctx.align) return ctx.column + (closing ? 0 : 1);
 | 
			
		||||
      else return ctx.indented + (closing ? 0 : indentUnit);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    electricChars: "{}):",
 | 
			
		||||
    fold: "brace",
 | 
			
		||||
    blockCommentStart: "/*",
 | 
			
		||||
    blockCommentEnd: "*/",
 | 
			
		||||
    lineComment: "//"
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
CodeMirror.defineMIME("text/x-go", "go");
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										117
									
								
								ethereal/assets/muted/lib/matchbrackets.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,117 @@
 | 
			
		||||
(function(mod) {
 | 
			
		||||
  if (typeof exports == "object" && typeof module == "object") // CommonJS
 | 
			
		||||
    mod(require("../../lib/codemirror"));
 | 
			
		||||
  else if (typeof define == "function" && define.amd) // AMD
 | 
			
		||||
    define(["../../lib/codemirror"], mod);
 | 
			
		||||
  else // Plain browser env
 | 
			
		||||
    mod(CodeMirror);
 | 
			
		||||
})(function(CodeMirror) {
 | 
			
		||||
  var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
 | 
			
		||||
    (document.documentMode == null || document.documentMode < 8);
 | 
			
		||||
 | 
			
		||||
  var Pos = CodeMirror.Pos;
 | 
			
		||||
 | 
			
		||||
  var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
 | 
			
		||||
 | 
			
		||||
  function findMatchingBracket(cm, where, strict, config) {
 | 
			
		||||
    var line = cm.getLineHandle(where.line), pos = where.ch - 1;
 | 
			
		||||
    var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
 | 
			
		||||
    if (!match) return null;
 | 
			
		||||
    var dir = match.charAt(1) == ">" ? 1 : -1;
 | 
			
		||||
    if (strict && (dir > 0) != (pos == where.ch)) return null;
 | 
			
		||||
    var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
 | 
			
		||||
 | 
			
		||||
    var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
 | 
			
		||||
    if (found == null) return null;
 | 
			
		||||
    return {from: Pos(where.line, pos), to: found && found.pos,
 | 
			
		||||
            match: found && found.ch == match.charAt(0), forward: dir > 0};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // bracketRegex is used to specify which type of bracket to scan
 | 
			
		||||
  // should be a regexp, e.g. /[[\]]/
 | 
			
		||||
  //
 | 
			
		||||
  // Note: If "where" is on an open bracket, then this bracket is ignored.
 | 
			
		||||
  //
 | 
			
		||||
  // Returns false when no bracket was found, null when it reached
 | 
			
		||||
  // maxScanLines and gave up
 | 
			
		||||
  function scanForBracket(cm, where, dir, style, config) {
 | 
			
		||||
    var maxScanLen = (config && config.maxScanLineLength) || 10000;
 | 
			
		||||
    var maxScanLines = (config && config.maxScanLines) || 1000;
 | 
			
		||||
 | 
			
		||||
    var stack = [];
 | 
			
		||||
    var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
 | 
			
		||||
    var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
 | 
			
		||||
                          : Math.max(cm.firstLine() - 1, where.line - maxScanLines);
 | 
			
		||||
    for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
 | 
			
		||||
      var line = cm.getLine(lineNo);
 | 
			
		||||
      if (!line) continue;
 | 
			
		||||
      var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
 | 
			
		||||
      if (line.length > maxScanLen) continue;
 | 
			
		||||
      if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
 | 
			
		||||
      for (; pos != end; pos += dir) {
 | 
			
		||||
        var ch = line.charAt(pos);
 | 
			
		||||
        if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
 | 
			
		||||
          var match = matching[ch];
 | 
			
		||||
          if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
 | 
			
		||||
          else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
 | 
			
		||||
          else stack.pop();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function matchBrackets(cm, autoclear, config) {
 | 
			
		||||
    // Disable brace matching in long lines, since it'll cause hugely slow updates
 | 
			
		||||
    var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
 | 
			
		||||
    var marks = [], ranges = cm.listSelections();
 | 
			
		||||
    for (var i = 0; i < ranges.length; i++) {
 | 
			
		||||
      var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
 | 
			
		||||
      if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
 | 
			
		||||
        var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
 | 
			
		||||
        marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
 | 
			
		||||
        if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
 | 
			
		||||
          marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (marks.length) {
 | 
			
		||||
      // Kludge to work around the IE bug from issue #1193, where text
 | 
			
		||||
      // input stops going to the textare whever this fires.
 | 
			
		||||
      if (ie_lt8 && cm.state.focused) cm.display.input.focus();
 | 
			
		||||
 | 
			
		||||
      var clear = function() {
 | 
			
		||||
        cm.operation(function() {
 | 
			
		||||
          for (var i = 0; i < marks.length; i++) marks[i].clear();
 | 
			
		||||
        });
 | 
			
		||||
      };
 | 
			
		||||
      if (autoclear) setTimeout(clear, 800);
 | 
			
		||||
      else return clear;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var currentlyHighlighted = null;
 | 
			
		||||
  function doMatchBrackets(cm) {
 | 
			
		||||
    cm.operation(function() {
 | 
			
		||||
      if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
 | 
			
		||||
      currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
 | 
			
		||||
    if (old && old != CodeMirror.Init)
 | 
			
		||||
      cm.off("cursorActivity", doMatchBrackets);
 | 
			
		||||
    if (val) {
 | 
			
		||||
      cm.state.matchBrackets = typeof val == "object" ? val : {};
 | 
			
		||||
      cm.on("cursorActivity", doMatchBrackets);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
 | 
			
		||||
  CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
 | 
			
		||||
    return findMatchingBracket(this, pos, strict, config);
 | 
			
		||||
  });
 | 
			
		||||
  CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
 | 
			
		||||
    return scanForBracket(this, pos, dir, style, config);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										61
									
								
								ethereal/assets/muted/muted.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,61 @@
 | 
			
		||||
// Helper function for generating pseudo callbacks and sending data to the QML part of the application
 | 
			
		||||
function postData(data, cb) {
 | 
			
		||||
	data._seed = Math.floor(Math.random() * 1000000)
 | 
			
		||||
	if(cb) {
 | 
			
		||||
		Muted._callbacks[data._seed] = cb;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(data.args === undefined) {
 | 
			
		||||
		data.args = [];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	navigator.qt.postMessage(JSON.stringify(data));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
window.Muted = {
 | 
			
		||||
	prototype: Object(),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
window.Muted._callbacks = {}
 | 
			
		||||
window.Muted._onCallbacks = {}
 | 
			
		||||
 | 
			
		||||
function debug(/**/) {
 | 
			
		||||
	console.log("hello world")
 | 
			
		||||
 | 
			
		||||
	var args = arguments;
 | 
			
		||||
	var msg = ""
 | 
			
		||||
	for(var i = 0; i < args.length; i++){
 | 
			
		||||
		if(typeof args[i] == "object") {
 | 
			
		||||
			msg += " " + JSON.stringify(args[i])
 | 
			
		||||
		} else {
 | 
			
		||||
			msg += args[i]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	document.querySelector("#debugger").innerHTML += "<div class='line'><div class='col1'></div><div class='col2'>"+msg+"</div></div>";
 | 
			
		||||
}
 | 
			
		||||
console.log = function() {
 | 
			
		||||
	var args = []
 | 
			
		||||
	for(var i = 0; i < arguments.length; i++) {
 | 
			
		||||
		args.push(arguments[i]);
 | 
			
		||||
	}
 | 
			
		||||
	postData({call:"log", args:args})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
navigator.qt.onmessage = function(ev) {
 | 
			
		||||
	var data = JSON.parse(ev.data)
 | 
			
		||||
 | 
			
		||||
	if(data._event !== undefined) {
 | 
			
		||||
		Muted.trigger(data._event, data.data);
 | 
			
		||||
	} else {
 | 
			
		||||
		if(data._seed) {
 | 
			
		||||
			var cb = Muted._callbacks[data._seed];
 | 
			
		||||
			if(cb) {
 | 
			
		||||
				// Call the callback
 | 
			
		||||
				cb(data.data);
 | 
			
		||||
				// Remove the "trigger" callback
 | 
			
		||||
				delete Muted._callbacks[ev._seed];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								ethereal/assets/net.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								ethereal/assets/network.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								ethereal/assets/new.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.7 KiB  | 
							
								
								
									
										22
									
								
								ethereal/assets/qml/QmlApp.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
import QtQuick 2.0
 | 
			
		||||
import QtQuick.Controls 1.0;
 | 
			
		||||
import QtQuick.Layouts 1.0;
 | 
			
		||||
import Ethereum 1.0
 | 
			
		||||
 | 
			
		||||
ApplicationWindow {
 | 
			
		||||
	minimumWidth: 500
 | 
			
		||||
	maximumWidth: 500
 | 
			
		||||
	maximumHeight: 400
 | 
			
		||||
	minimumHeight: 400
 | 
			
		||||
 | 
			
		||||
	function onNewBlockCb(block) {
 | 
			
		||||
		console.log("Please overwrite onNewBlock(block):", block)
 | 
			
		||||
	}
 | 
			
		||||
	function onObjectChangeCb(stateObject) {
 | 
			
		||||
		console.log("Please overwrite onObjectChangeCb(object)", stateObject)
 | 
			
		||||
	}
 | 
			
		||||
	function onStorageChangeCb(storageObject) {
 | 
			
		||||
		var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
 | 
			
		||||
		console.log("Please overwrite onStorageChangeCb(object)", ev)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										155
									
								
								ethereal/assets/qml/first_run.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,155 @@
 | 
			
		||||
import QtQuick 2.0
 | 
			
		||||
import Ethereum 1.0
 | 
			
		||||
 | 
			
		||||
// Which ones do we actually need?
 | 
			
		||||
import QtQuick.Controls 1.0;
 | 
			
		||||
import QtQuick.Layouts 1.0;
 | 
			
		||||
import QtQuick.Dialogs 1.0;
 | 
			
		||||
import QtQuick.Window 2.1;
 | 
			
		||||
import QtQuick.Controls.Styles 1.1
 | 
			
		||||
import QtQuick.Dialogs 1.1
 | 
			
		||||
 | 
			
		||||
ApplicationWindow {
 | 
			
		||||
    id: wizardRoot
 | 
			
		||||
    width: 500
 | 
			
		||||
    height: 400
 | 
			
		||||
    title: "Ethereal first run setup"
 | 
			
		||||
 | 
			
		||||
    Column {
 | 
			
		||||
        spacing: 5
 | 
			
		||||
        anchors.leftMargin: 10
 | 
			
		||||
        anchors.left: parent.left
 | 
			
		||||
 | 
			
		||||
        Text {
 | 
			
		||||
            visible: true
 | 
			
		||||
            text: "<h2>Ethereal setup</h2>"
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Column {
 | 
			
		||||
            id: restoreColumn
 | 
			
		||||
            spacing: 5
 | 
			
		||||
            Text {
 | 
			
		||||
                visible: true
 | 
			
		||||
                font.pointSize: 14
 | 
			
		||||
                text: "Restore your Ethereum account"
 | 
			
		||||
                id: restoreLabel
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            TextField {
 | 
			
		||||
                id: txPrivKey
 | 
			
		||||
                width: 480
 | 
			
		||||
                placeholderText: "Private key or mnemonic words"
 | 
			
		||||
                focus: true
 | 
			
		||||
                onTextChanged: {
 | 
			
		||||
                    if(this.text.length == 64){
 | 
			
		||||
                        detailLabel.text = "Private (hex) key detected."
 | 
			
		||||
                        actionButton.enabled = true
 | 
			
		||||
                    }
 | 
			
		||||
                    else if(this.text.split(" ").length == 24){
 | 
			
		||||
                        detailLabel.text = "Mnemonic key detected."
 | 
			
		||||
                        actionButton.enabled = true
 | 
			
		||||
                    }else{
 | 
			
		||||
                        detailLabel.text = ""
 | 
			
		||||
                        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 {
 | 
			
		||||
            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 {
 | 
			
		||||
        anchors.right: parent.right
 | 
			
		||||
        anchors.bottom: parent.bottom
 | 
			
		||||
        anchors.rightMargin: 10
 | 
			
		||||
        anchors.bottomMargin: 10
 | 
			
		||||
        id: newKey
 | 
			
		||||
        text: "I don't have an account yet"
 | 
			
		||||
        onClicked: {
 | 
			
		||||
            var res = lib.createAndSetPrivKey()
 | 
			
		||||
            mnemonicInput.text = res[0]
 | 
			
		||||
            addressInput.text = res[1]
 | 
			
		||||
            privkeyInput.text = res[2]
 | 
			
		||||
 | 
			
		||||
            // Hide restore
 | 
			
		||||
            restoreColumn.visible = false
 | 
			
		||||
 | 
			
		||||
            // Show new details
 | 
			
		||||
            newDetailsColumn.visible = true
 | 
			
		||||
            newKey.visible = false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								ethereal/assets/qml/muted.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,74 @@
 | 
			
		||||
import QtQuick 2.0
 | 
			
		||||
import QtWebKit 3.0
 | 
			
		||||
import QtWebKit.experimental 1.0
 | 
			
		||||
import QtQuick.Controls 1.0;
 | 
			
		||||
import QtQuick.Layouts 1.0;
 | 
			
		||||
import QtQuick.Window 2.1;
 | 
			
		||||
import Ethereum 1.0
 | 
			
		||||
 | 
			
		||||
ApplicationWindow {
 | 
			
		||||
    id: window
 | 
			
		||||
    title: "muted"
 | 
			
		||||
    width: 900
 | 
			
		||||
    height: 600
 | 
			
		||||
    minimumHeight: 300
 | 
			
		||||
 | 
			
		||||
    property alias url: webView.url
 | 
			
		||||
    property alias webView: webView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Item {
 | 
			
		||||
        id: root
 | 
			
		||||
        anchors.fill: parent
 | 
			
		||||
        WebView {
 | 
			
		||||
            objectName: "webView"
 | 
			
		||||
            id: webView
 | 
			
		||||
            anchors {
 | 
			
		||||
                top: root.top
 | 
			
		||||
                right: root.right
 | 
			
		||||
                left: root.left
 | 
			
		||||
                bottom: root.bottom
 | 
			
		||||
                //bottom: sizeGrip.top
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            experimental.preferences.javascriptEnabled: true
 | 
			
		||||
            experimental.preferences.navigatorQtObjectEnabled: true
 | 
			
		||||
            experimental.onMessageReceived: {
 | 
			
		||||
                var data = JSON.parse(message.data)
 | 
			
		||||
 | 
			
		||||
                switch(data.call) {
 | 
			
		||||
                case "log":
 | 
			
		||||
                    console.log.apply(this, data.args)
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            function postData(seed, data) {
 | 
			
		||||
                webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed}))
 | 
			
		||||
            }
 | 
			
		||||
            function postEvent(event, data) {
 | 
			
		||||
                webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        Rectangle {
 | 
			
		||||
            id: sizeGrip
 | 
			
		||||
            color: "gray"
 | 
			
		||||
            height: 5
 | 
			
		||||
            anchors {
 | 
			
		||||
                left: root.left
 | 
			
		||||
                right: root.right
 | 
			
		||||
            }
 | 
			
		||||
            y: Math.round(root.height * 2 / 3)
 | 
			
		||||
 | 
			
		||||
            MouseArea {
 | 
			
		||||
                anchors.fill: parent
 | 
			
		||||
                drag.target: sizeGrip
 | 
			
		||||
                drag.minimumY: 0
 | 
			
		||||
                drag.maximumY: root.height - sizeGrip.height
 | 
			
		||||
                drag.axis: Drag.YAxis
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								ethereal/assets/qml/test_app.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,70 @@
 | 
			
		||||
import QtQuick 2.0
 | 
			
		||||
import QtQuick.Controls 1.0;
 | 
			
		||||
import QtQuick.Layouts 1.0;
 | 
			
		||||
import Ethereum 1.0
 | 
			
		||||
 | 
			
		||||
QmlApp {
 | 
			
		||||
	minimumWidth: 350
 | 
			
		||||
	maximumWidth: 350
 | 
			
		||||
	maximumHeight: 80
 | 
			
		||||
	minimumHeight: 80
 | 
			
		||||
 | 
			
		||||
	title: "Generic Coin"
 | 
			
		||||
 | 
			
		||||
	property string contractAddr: "f299f6c74515620e4c4cd8fe3d205b5c4f2e25c8"
 | 
			
		||||
	property string addr: "2ef47100e0787b915105fd5e3f4ff6752079d5cb"
 | 
			
		||||
 | 
			
		||||
	Component.onCompleted: {
 | 
			
		||||
		eth.watch(contractAddr, addr)
 | 
			
		||||
		eth.watch(addr, contractAddr)
 | 
			
		||||
		setAmount()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function onStorageChangeCb(storageObject) {
 | 
			
		||||
		setAmount()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function setAmount(){
 | 
			
		||||
		var state = eth.getStateObject(contractAddr)
 | 
			
		||||
		var storage = state.getStorage(addr)
 | 
			
		||||
		amountLabel.text = storage
 | 
			
		||||
	}
 | 
			
		||||
	Column {
 | 
			
		||||
		spacing: 5
 | 
			
		||||
		Row {
 | 
			
		||||
			spacing: 20
 | 
			
		||||
			Label {
 | 
			
		||||
				id: genLabel
 | 
			
		||||
				text: "Generic coin balance:"
 | 
			
		||||
			}
 | 
			
		||||
			Label {
 | 
			
		||||
				id: amountLabel
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		Row {
 | 
			
		||||
			spacing: 20
 | 
			
		||||
			TextField {
 | 
			
		||||
				id: address
 | 
			
		||||
				placeholderText: "Address"
 | 
			
		||||
			}
 | 
			
		||||
			TextField {
 | 
			
		||||
				id: amount
 | 
			
		||||
				placeholderText: "Amount"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		Button {
 | 
			
		||||
			text: "Send coins"
 | 
			
		||||
			onClicked: {
 | 
			
		||||
				var privKey = eth.getKey().privateKey
 | 
			
		||||
				if(privKey){
 | 
			
		||||
					var result = eth.transact(privKey, contractAddr, 0,"100000","250", "0x" + address.text + "\n" + amount.text)
 | 
			
		||||
					resultTx.text = result.hash
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		Label {
 | 
			
		||||
			id: resultTx
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								ethereal/assets/qml/transactions.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,9 @@
 | 
			
		||||
import QtQuick 2.0
 | 
			
		||||
import QtQuick.Controls 1.0;
 | 
			
		||||
import QtQuick.Layouts 1.0;
 | 
			
		||||
 | 
			
		||||
Rectangle {
 | 
			
		||||
	id: transactionView
 | 
			
		||||
	visible: false
 | 
			
		||||
	Text { text: "TX VIEW" }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1075
									
								
								ethereal/assets/qml/wallet.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										246
									
								
								ethereal/assets/qml/webapp.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,246 @@
 | 
			
		||||
import QtQuick 2.0
 | 
			
		||||
import QtWebKit 3.0
 | 
			
		||||
import QtWebKit.experimental 1.0
 | 
			
		||||
import QtQuick.Controls 1.0;
 | 
			
		||||
import QtQuick.Layouts 1.0;
 | 
			
		||||
import QtQuick.Window 2.1;
 | 
			
		||||
import Ethereum 1.0
 | 
			
		||||
 | 
			
		||||
ApplicationWindow {
 | 
			
		||||
	id: window
 | 
			
		||||
	title: "Ethereum"
 | 
			
		||||
	width: 900
 | 
			
		||||
	height: 600
 | 
			
		||||
	minimumHeight: 300
 | 
			
		||||
 | 
			
		||||
	property alias url: webview.url
 | 
			
		||||
	property alias webView: webview
 | 
			
		||||
 | 
			
		||||
	Item {
 | 
			
		||||
		objectName: "root"
 | 
			
		||||
		id: root
 | 
			
		||||
		anchors.fill: parent
 | 
			
		||||
		state: "inspectorShown"
 | 
			
		||||
 | 
			
		||||
		WebView {
 | 
			
		||||
			objectName: "webView"
 | 
			
		||||
			id: webview
 | 
			
		||||
			anchors.fill: parent
 | 
			
		||||
			/*
 | 
			
		||||
			 anchors {
 | 
			
		||||
				 left: parent.left
 | 
			
		||||
				 right: parent.right
 | 
			
		||||
				 bottom: sizeGrip.top
 | 
			
		||||
				 top: parent.top
 | 
			
		||||
			 }
 | 
			
		||||
			 */
 | 
			
		||||
			onTitleChanged: { window.title = title }
 | 
			
		||||
			experimental.preferences.javascriptEnabled: true
 | 
			
		||||
			experimental.preferences.navigatorQtObjectEnabled: true
 | 
			
		||||
			experimental.preferences.developerExtrasEnabled: true
 | 
			
		||||
			experimental.userScripts: [ui.assetPath("ext/pre.js"), ui.assetPath("ext/big.js"), ui.assetPath("ext/string.js"), ui.assetPath("ext/ethereum.js")]
 | 
			
		||||
			experimental.onMessageReceived: {
 | 
			
		||||
				console.log("[onMessageReceived]: ", message.data)
 | 
			
		||||
				// TODO move to messaging.js
 | 
			
		||||
				var data = JSON.parse(message.data)
 | 
			
		||||
 | 
			
		||||
				try {
 | 
			
		||||
					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":
 | 
			
		||||
						var block = eth.getBlock(data.args[0])
 | 
			
		||||
						postData(data._seed, block)
 | 
			
		||||
 | 
			
		||||
						break
 | 
			
		||||
					case "getBlockByHash":
 | 
			
		||||
						var block = eth.getBlock(data.args[0])
 | 
			
		||||
						postData(data._seed, block)
 | 
			
		||||
 | 
			
		||||
						break
 | 
			
		||||
					case "transact":
 | 
			
		||||
						require(5)
 | 
			
		||||
 | 
			
		||||
						var tx = eth.transact(data.args[0], data.args[1], data.args[2],data.args[3],data.args[4],data.args[5])
 | 
			
		||||
						postData(data._seed, tx)
 | 
			
		||||
 | 
			
		||||
						break
 | 
			
		||||
					case "create":
 | 
			
		||||
						postData(data._seed, null)
 | 
			
		||||
 | 
			
		||||
						break
 | 
			
		||||
					case "getStorage":
 | 
			
		||||
						require(2);
 | 
			
		||||
 | 
			
		||||
						var stateObject = eth.getStateObject(data.args[0])
 | 
			
		||||
						var storage = stateObject.getStorage(data.args[1])
 | 
			
		||||
						postData(data._seed, storage)
 | 
			
		||||
 | 
			
		||||
						break
 | 
			
		||||
					case "getStateKeyVals":
 | 
			
		||||
					      require(1);
 | 
			
		||||
					      var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
 | 
			
		||||
					      postData(data._seed,stateObject)
 | 
			
		||||
 | 
			
		||||
						break
 | 
			
		||||
					case "getTransactionsFor":
 | 
			
		||||
					      require(1);
 | 
			
		||||
					      var txs = eth.getTransactionsFor(data.args[0], true)
 | 
			
		||||
					      postData(data._seed, txs)
 | 
			
		||||
 | 
			
		||||
					      break
 | 
			
		||||
					case "getBalance":
 | 
			
		||||
						require(1);
 | 
			
		||||
 | 
			
		||||
						postData(data._seed, eth.getStateObject(data.args[0]).value());
 | 
			
		||||
 | 
			
		||||
						break
 | 
			
		||||
					case "getKey":
 | 
			
		||||
						var key = eth.getKey().privateKey;
 | 
			
		||||
 | 
			
		||||
						postData(data._seed, key)
 | 
			
		||||
						break
 | 
			
		||||
					case "watch":
 | 
			
		||||
						require(1)
 | 
			
		||||
						eth.watch(data.args[0], data.args[1]);
 | 
			
		||||
						break
 | 
			
		||||
					case "disconnect":
 | 
			
		||||
						require(1)
 | 
			
		||||
						postData(data._seed, null)
 | 
			
		||||
						break;
 | 
			
		||||
					case "set":
 | 
			
		||||
            console.log("'Set' has been depcrecated")
 | 
			
		||||
          /*
 | 
			
		||||
						for(var key in data.args) {
 | 
			
		||||
							if(webview.hasOwnProperty(key)) {
 | 
			
		||||
								window[key] = data.args[key];
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
            */
 | 
			
		||||
						break;
 | 
			
		||||
					case "getSecretToAddress":
 | 
			
		||||
						require(1)
 | 
			
		||||
						postData(data._seed, eth.secretToAddress(data.args[0]))
 | 
			
		||||
						break;
 | 
			
		||||
					case "debug":
 | 
			
		||||
						console.log(data.args[0]);
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				} catch(e) {
 | 
			
		||||
					console.log(data.call + ": " + e)
 | 
			
		||||
 | 
			
		||||
					postData(data._seed, null);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			function require(args, num) {
 | 
			
		||||
				if(args.length < num) {
 | 
			
		||||
					throw("required argument count of "+num+" got "+args.length);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			function postData(seed, data) {
 | 
			
		||||
				webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed}))
 | 
			
		||||
			}
 | 
			
		||||
			function postEvent(event, data) {
 | 
			
		||||
				webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			function onNewBlockCb(block) {
 | 
			
		||||
				postEvent("block:new", block)
 | 
			
		||||
			}
 | 
			
		||||
			function onObjectChangeCb(stateObject) {
 | 
			
		||||
				postEvent("object:"+stateObject.address(), stateObject)
 | 
			
		||||
			}
 | 
			
		||||
			function onStorageChangeCb(storageObject) {
 | 
			
		||||
				var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
 | 
			
		||||
				postEvent(ev, [storageObject.address, storageObject.value])
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		Rectangle {
 | 
			
		||||
			id: toggleInspector
 | 
			
		||||
			color: "#bcbcbc"
 | 
			
		||||
			visible: true
 | 
			
		||||
			height: 12
 | 
			
		||||
			width: 12
 | 
			
		||||
			anchors {
 | 
			
		||||
				right: root.right
 | 
			
		||||
			}
 | 
			
		||||
			MouseArea {
 | 
			
		||||
				onClicked: {
 | 
			
		||||
					if(inspector.visible == true){
 | 
			
		||||
						inspector.visible = false
 | 
			
		||||
					}else{
 | 
			
		||||
						inspector.visible = true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				onDoubleClicked: {
 | 
			
		||||
				  console.log('refreshing')
 | 
			
		||||
				  webView.reload()
 | 
			
		||||
				}
 | 
			
		||||
				anchors.fill: parent
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Rectangle {
 | 
			
		||||
			id: sizeGrip
 | 
			
		||||
			color: "gray"
 | 
			
		||||
			visible: false
 | 
			
		||||
			height: 10
 | 
			
		||||
			anchors {
 | 
			
		||||
				left: root.left
 | 
			
		||||
				right: root.right
 | 
			
		||||
			}
 | 
			
		||||
			y: Math.round(root.height * 2 / 3)
 | 
			
		||||
 | 
			
		||||
			MouseArea {
 | 
			
		||||
				anchors.fill: parent
 | 
			
		||||
				drag.target: sizeGrip
 | 
			
		||||
				drag.minimumY: 0
 | 
			
		||||
				drag.maximumY: root.height
 | 
			
		||||
				drag.axis: Drag.YAxis
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		WebView {
 | 
			
		||||
			id: inspector
 | 
			
		||||
			visible: false
 | 
			
		||||
			url: webview.experimental.remoteInspectorUrl
 | 
			
		||||
			anchors {
 | 
			
		||||
				left: root.left
 | 
			
		||||
				right: root.right
 | 
			
		||||
				top: sizeGrip.bottom
 | 
			
		||||
				bottom: root.bottom
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		states: [
 | 
			
		||||
			State {
 | 
			
		||||
				name: "inspectorShown"
 | 
			
		||||
				PropertyChanges {
 | 
			
		||||
					target: inspector
 | 
			
		||||
					url: webview.experimental.remoteInspectorUrl
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								ethereal/assets/samplecoin/bootstrap-theme.min.css
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
							
								
								
									
										7
									
								
								ethereal/assets/samplecoin/bootstrap.min.css
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								ethereal/assets/samplecoin/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 85 KiB  | 
							
								
								
									
										34
									
								
								ethereal/assets/samplecoin/samplecoin.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,34 @@
 | 
			
		||||
/* Space out content a bit */
 | 
			
		||||
body {
 | 
			
		||||
	padding-top: 20px;
 | 
			
		||||
	padding-bottom: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Everything but the jumbotron gets side spacing for mobile first
 | 
			
		||||
 * views */
 | 
			
		||||
.header,
 | 
			
		||||
.marketing,
 | 
			
		||||
.footer {
 | 
			
		||||
	padding-right: 15px;
 | 
			
		||||
	padding-left: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Custom page header */
 | 
			
		||||
.header {
 | 
			
		||||
	border-bottom: 1px solid #e5e5e5;
 | 
			
		||||
}
 | 
			
		||||
/* Make the masthead heading the same height as the navigation */
 | 
			
		||||
.header h3 {
 | 
			
		||||
	padding-bottom: 19px;
 | 
			
		||||
	margin-top: 0;
 | 
			
		||||
	margin-bottom: 0;
 | 
			
		||||
	line-height: 40px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.jumbotron {
 | 
			
		||||
	text-align: center;
 | 
			
		||||
	border-bottom: 1px solid #e5e5e5;
 | 
			
		||||
 | 
			
		||||
	margin: 0 auto;
 | 
			
		||||
	width: 300px;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								ethereal/assets/samplecoin/samplecoin.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,68 @@
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<title>jeffcoin</title>
 | 
			
		||||
 | 
			
		||||
<link rel="stylesheet" href="bootstrap.min.css">
 | 
			
		||||
<link rel="stylesheet" href="bootstrap-theme.min.css">
 | 
			
		||||
<link rel="stylesheet" href="samplecoin.css">
 | 
			
		||||
<meta name="viewport" content="minimum-scale=1; maximum-scale=1; initial-scale=1;">
 | 
			
		||||
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
 | 
			
		||||
var jefcoinAddr = "22fa3ebce6ef9ca661a960104d3087eec040011e"
 | 
			
		||||
var mAddr = ""
 | 
			
		||||
 | 
			
		||||
function createTransaction() {
 | 
			
		||||
	var addr = ("0x" + document.querySelector("#addr").value).pad(32);
 | 
			
		||||
	var amount = document.querySelector("#amount").value.pad(32);
 | 
			
		||||
 | 
			
		||||
	var data = (addr + amount).unbin();
 | 
			
		||||
	eth.transact(mAddr, jefcoinAddr, 0, "50000", "1000000", data, function(receipt) {
 | 
			
		||||
		debug("received tx hash:", reciept.address)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
	eth.getKey(function(sec) {
 | 
			
		||||
		mAddr = sec;
 | 
			
		||||
		eth.getSecretToAddress(sec, function(addr) {
 | 
			
		||||
			eth.getStorageAt(jefcoinAddr, addr, function(storage) {
 | 
			
		||||
				document.querySelector("#current-amount").innerHTML = storage;
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			eth.watch(jefcoinAddr, addr, function(addr, value) {
 | 
			
		||||
				document.querySelector("#current-amount").innerHTML = value
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body onload="init();">
 | 
			
		||||
<div class="container">
 | 
			
		||||
	<div class="header">
 | 
			
		||||
		<h3 class="text-muted">JeffCoin</h3>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class="jumbotron ">
 | 
			
		||||
		<img src="icon.png">
 | 
			
		||||
		<div>Amount: <strong id="current-amount"></strong></div>
 | 
			
		||||
 | 
			
		||||
		<div id="transactions">
 | 
			
		||||
			<div class="form-group">
 | 
			
		||||
				<input id="addr" class="form-control" type="text" placeholder="Receiver address"></input><br>
 | 
			
		||||
				<input id="amount" class="form-control" type="text" placeholder="Amount"></input><br>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<button class="btn btn-default" onclick="createTransaction();">Send Tx</button>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div id="debug" style="border: 1px solid black; min-height: 30px;"></div>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								ethereal/assets/tx.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.0 KiB  | 
							
								
								
									
										43
									
								
								ethereal/assets/util/test.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -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>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										99
									
								
								ethereal/flags.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,99 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bitbucket.org/kardianos/osext"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethlog"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/user"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var Identifier string
 | 
			
		||||
var KeyRing string
 | 
			
		||||
var KeyStore string
 | 
			
		||||
var StartRpc bool
 | 
			
		||||
var RpcPort int
 | 
			
		||||
var UseUPnP bool
 | 
			
		||||
var OutboundPort string
 | 
			
		||||
var ShowGenesis bool
 | 
			
		||||
var AddPeer string
 | 
			
		||||
var MaxPeer int
 | 
			
		||||
var GenAddr bool
 | 
			
		||||
var UseSeed bool
 | 
			
		||||
var SecretFile string
 | 
			
		||||
var ExportDir string
 | 
			
		||||
var NonInteractive bool
 | 
			
		||||
var Datadir string
 | 
			
		||||
var LogFile string
 | 
			
		||||
var ConfigFile string
 | 
			
		||||
var DebugFile string
 | 
			
		||||
var LogLevel int
 | 
			
		||||
 | 
			
		||||
// flags specific to gui client
 | 
			
		||||
var AssetPath string
 | 
			
		||||
 | 
			
		||||
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", "ethereal") {
 | 
			
		||||
		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/ethereal"
 | 
			
		||||
		case "window":
 | 
			
		||||
			fallthrough
 | 
			
		||||
		default:
 | 
			
		||||
			assetPath = "."
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return assetPath
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func defaultDataDir() string {
 | 
			
		||||
	usr, _ := user.Current()
 | 
			
		||||
	return path.Join(usr.HomeDir, ".ethereal")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
 | 
			
		||||
 | 
			
		||||
func Init() {
 | 
			
		||||
	flag.Usage = func() {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0])
 | 
			
		||||
		flag.PrintDefaults()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flag.StringVar(&Identifier, "id", "", "Custom client identifier")
 | 
			
		||||
	flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
 | 
			
		||||
	flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)")
 | 
			
		||||
	flag.StringVar(&OutboundPort, "port", "30303", "listening port")
 | 
			
		||||
	flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
 | 
			
		||||
	flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
 | 
			
		||||
	flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
 | 
			
		||||
	flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
 | 
			
		||||
	flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
 | 
			
		||||
	flag.BoolVar(&UseSeed, "seed", true, "seed peers")
 | 
			
		||||
	flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
 | 
			
		||||
	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(&ConfigFile, "conf", defaultConfigFile, "config file")
 | 
			
		||||
	flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
 | 
			
		||||
	flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
 | 
			
		||||
 | 
			
		||||
	flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory")
 | 
			
		||||
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								ethereal/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,66 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/ethereum/eth-go/ethlog"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/ethereal/ui"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/utils"
 | 
			
		||||
	"github.com/go-qml/qml"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	// Leave QT on top at ALL times. Qt Needs to be initialized from the main thread
 | 
			
		||||
	qml.Init(nil)
 | 
			
		||||
 | 
			
		||||
	runtime.GOMAXPROCS(runtime.NumCPU())
 | 
			
		||||
 | 
			
		||||
	var interrupted = false
 | 
			
		||||
	utils.RegisterInterrupt(func(os.Signal) {
 | 
			
		||||
		interrupted = true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	utils.HandleInterrupt()
 | 
			
		||||
 | 
			
		||||
	// precedence: code-internal flag default < config file < environment variables < command line
 | 
			
		||||
	Init() // parsing command line
 | 
			
		||||
	utils.InitConfig(ConfigFile, Datadir, Identifier, "ETH")
 | 
			
		||||
 | 
			
		||||
	utils.InitDataDir(Datadir)
 | 
			
		||||
 | 
			
		||||
	utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile)
 | 
			
		||||
 | 
			
		||||
	db := utils.NewDatabase()
 | 
			
		||||
 | 
			
		||||
	keyManager := utils.NewKeyManager(KeyStore, Datadir, db)
 | 
			
		||||
 | 
			
		||||
	// create, import, export keys
 | 
			
		||||
	utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
 | 
			
		||||
 | 
			
		||||
	ethereum := utils.NewEthereum(db, keyManager, UseUPnP, OutboundPort, MaxPeer)
 | 
			
		||||
 | 
			
		||||
	if ShowGenesis {
 | 
			
		||||
		utils.ShowGenesis(ethereum)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if StartRpc {
 | 
			
		||||
		utils.StartRpc(ethereum, RpcPort)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gui := ethui.New(ethereum, KeyRing, LogLevel)
 | 
			
		||||
 | 
			
		||||
	utils.RegisterInterrupt(func(os.Signal) {
 | 
			
		||||
		gui.Stop()
 | 
			
		||||
	})
 | 
			
		||||
	utils.StartEthereum(ethereum, UseSeed)
 | 
			
		||||
	// gui blocks the main thread
 | 
			
		||||
	gui.Start(AssetPath)
 | 
			
		||||
	// we need to run the interrupt callbacks in case gui is closed
 | 
			
		||||
	// this skips if we got here by actual interrupt stopping the GUI
 | 
			
		||||
	if !interrupted {
 | 
			
		||||
		utils.RunInterruptCallbacks(os.Interrupt)
 | 
			
		||||
	}
 | 
			
		||||
	// this blocks the thread
 | 
			
		||||
	ethereum.WaitForShutdown()
 | 
			
		||||
	ethlog.Flush()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										234
									
								
								ethereal/ui/debugger.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,234 @@
 | 
			
		||||
package ethui
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethchain"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"github.com/go-qml/qml"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type DebuggerWindow struct {
 | 
			
		||||
	win    *qml.Window
 | 
			
		||||
	engine *qml.Engine
 | 
			
		||||
	lib    *UiLib
 | 
			
		||||
	Db     *Debugger
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
 | 
			
		||||
	engine := qml.NewEngine()
 | 
			
		||||
	component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	win := component.CreateWindow(nil)
 | 
			
		||||
	db := &Debugger{win, make(chan bool), make(chan bool), true, false, true}
 | 
			
		||||
 | 
			
		||||
	return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebuggerWindow) Show() {
 | 
			
		||||
	context := self.engine.Context()
 | 
			
		||||
	context.SetVar("dbg", self)
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		self.win.Show()
 | 
			
		||||
		self.win.Wait()
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebuggerWindow) SetCode(code string) {
 | 
			
		||||
	self.win.Set("codeText", code)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebuggerWindow) SetData(data string) {
 | 
			
		||||
	self.win.Set("dataText", data)
 | 
			
		||||
}
 | 
			
		||||
func (self *DebuggerWindow) SetAsm(data string) {
 | 
			
		||||
	dis := ethchain.Disassemble(ethutil.Hex2Bytes(data))
 | 
			
		||||
	for _, str := range dis {
 | 
			
		||||
		self.win.Root().Call("setAsm", str)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
 | 
			
		||||
	if !self.Db.done {
 | 
			
		||||
		self.Db.Q <- true
 | 
			
		||||
	}
 | 
			
		||||
	self.Db.breakOnInstr = self.win.Root().ObjectByName("breakEachLine").Bool("checked")
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if r := recover(); r != nil {
 | 
			
		||||
			self.Logf("compile FAULT: %v", r)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	data := ethutil.StringToByteFunc(dataStr, func(s string) (ret []byte) {
 | 
			
		||||
		slice := strings.Split(dataStr, "\n")
 | 
			
		||||
		for _, dataItem := range slice {
 | 
			
		||||
			d := ethutil.FormatData(dataItem)
 | 
			
		||||
			ret = append(ret, d...)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
 | 
			
		||||
		ret, err = ethutil.Compile(s)
 | 
			
		||||
		return
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		self.Logln(err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dis := ethchain.Disassemble(script)
 | 
			
		||||
	self.win.Root().Call("clearAsm")
 | 
			
		||||
	self.win.Root().Call("clearLog")
 | 
			
		||||
 | 
			
		||||
	for _, str := range dis {
 | 
			
		||||
		self.win.Root().Call("setAsm", str)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		gas      = ethutil.Big(gasStr)
 | 
			
		||||
		gasPrice = ethutil.Big(gasPriceStr)
 | 
			
		||||
		value    = ethutil.Big(valueStr)
 | 
			
		||||
		// Contract addr as test address
 | 
			
		||||
		keyPair  = self.lib.eth.KeyManager().KeyPair()
 | 
			
		||||
		callerTx = ethchain.NewContractCreationTx(ethutil.Big(valueStr), gas, gasPrice, script)
 | 
			
		||||
	)
 | 
			
		||||
	callerTx.Sign(keyPair.PrivateKey)
 | 
			
		||||
 | 
			
		||||
	state := self.lib.eth.BlockChain().CurrentBlock.State()
 | 
			
		||||
	account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
 | 
			
		||||
	contract := ethchain.MakeContract(callerTx, state)
 | 
			
		||||
	contract.Amount = value
 | 
			
		||||
	callerClosure := ethchain.NewClosure(account, contract, script, state, gas, gasPrice)
 | 
			
		||||
 | 
			
		||||
	block := self.lib.eth.BlockChain().CurrentBlock
 | 
			
		||||
	vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
 | 
			
		||||
		Block:       block,
 | 
			
		||||
		Origin:      account.Address(),
 | 
			
		||||
		BlockNumber: block.Number,
 | 
			
		||||
		PrevHash:    block.PrevHash,
 | 
			
		||||
		Coinbase:    block.Coinbase,
 | 
			
		||||
		Time:        block.Time,
 | 
			
		||||
		Diff:        block.Difficulty,
 | 
			
		||||
		Value:       ethutil.Big(valueStr),
 | 
			
		||||
	})
 | 
			
		||||
	vm.Verbose = true
 | 
			
		||||
 | 
			
		||||
	self.Db.done = false
 | 
			
		||||
	self.Logf("callsize %d", len(script))
 | 
			
		||||
	go func() {
 | 
			
		||||
		ret, g, err := callerClosure.Call(vm, data, self.Db.halting)
 | 
			
		||||
		tot := new(big.Int).Mul(g, gasPrice)
 | 
			
		||||
		self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			self.Logln("exited with errors:", err)
 | 
			
		||||
		} else {
 | 
			
		||||
			if len(ret) > 0 {
 | 
			
		||||
				self.Logf("exited: % x", ret)
 | 
			
		||||
			} else {
 | 
			
		||||
				self.Logf("exited: nil")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		state.Reset()
 | 
			
		||||
 | 
			
		||||
		if !self.Db.interrupt {
 | 
			
		||||
			self.Db.done = true
 | 
			
		||||
		} else {
 | 
			
		||||
			self.Db.interrupt = false
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
 | 
			
		||||
	self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebuggerWindow) Logln(v ...interface{}) {
 | 
			
		||||
	str := fmt.Sprintln(v...)
 | 
			
		||||
	self.Logf("%s", str[:len(str)-1])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebuggerWindow) Next() {
 | 
			
		||||
	self.Db.Next()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Debugger struct {
 | 
			
		||||
	win             *qml.Window
 | 
			
		||||
	N               chan bool
 | 
			
		||||
	Q               chan bool
 | 
			
		||||
	done, interrupt bool
 | 
			
		||||
	breakOnInstr    bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type storeVal struct {
 | 
			
		||||
	Key, Value string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, stack *ethchain.Stack, stateObject *ethchain.StateObject) bool {
 | 
			
		||||
	d.win.Root().Call("setInstruction", pc)
 | 
			
		||||
	d.win.Root().Call("clearMem")
 | 
			
		||||
	d.win.Root().Call("clearStack")
 | 
			
		||||
	d.win.Root().Call("clearStorage")
 | 
			
		||||
 | 
			
		||||
	addr := 0
 | 
			
		||||
	for i := 0; i+32 <= mem.Len(); i += 32 {
 | 
			
		||||
		d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
 | 
			
		||||
		addr++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, val := range stack.Data() {
 | 
			
		||||
		d.win.Root().Call("setStack", val.String())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stateObject.State().EachStorage(func(key string, node *ethutil.Value) {
 | 
			
		||||
		d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if d.breakOnInstr {
 | 
			
		||||
	out:
 | 
			
		||||
		for {
 | 
			
		||||
			select {
 | 
			
		||||
			case <-d.N:
 | 
			
		||||
				break out
 | 
			
		||||
			case <-d.Q:
 | 
			
		||||
				d.interrupt = true
 | 
			
		||||
				d.clearBuffers()
 | 
			
		||||
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Debugger) clearBuffers() {
 | 
			
		||||
out:
 | 
			
		||||
	// drain
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-d.N:
 | 
			
		||||
		case <-d.Q:
 | 
			
		||||
		default:
 | 
			
		||||
			break out
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Debugger) Next() {
 | 
			
		||||
	if !d.done {
 | 
			
		||||
		d.N <- true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								ethereal/ui/ext_app.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,132 @@
 | 
			
		||||
package ethui
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethchain"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethpub"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"github.com/go-qml/qml"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AppContainer interface {
 | 
			
		||||
	Create() error
 | 
			
		||||
	Destroy()
 | 
			
		||||
 | 
			
		||||
	Window() *qml.Window
 | 
			
		||||
	Engine() *qml.Engine
 | 
			
		||||
 | 
			
		||||
	NewBlock(*ethchain.Block)
 | 
			
		||||
	ObjectChanged(*ethchain.StateObject)
 | 
			
		||||
	StorageChanged(*ethchain.StorageState)
 | 
			
		||||
	NewWatcher(chan bool)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ExtApplication struct {
 | 
			
		||||
	*ethpub.PEthereum
 | 
			
		||||
 | 
			
		||||
	blockChan       chan ethutil.React
 | 
			
		||||
	changeChan      chan ethutil.React
 | 
			
		||||
	quitChan        chan bool
 | 
			
		||||
	watcherQuitChan chan bool
 | 
			
		||||
 | 
			
		||||
	container        AppContainer
 | 
			
		||||
	lib              *UiLib
 | 
			
		||||
	registeredEvents []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication {
 | 
			
		||||
	app := &ExtApplication{
 | 
			
		||||
		ethpub.NewPEthereum(lib.eth),
 | 
			
		||||
		make(chan ethutil.React, 1),
 | 
			
		||||
		make(chan ethutil.React, 1),
 | 
			
		||||
		make(chan bool),
 | 
			
		||||
		make(chan bool),
 | 
			
		||||
		container,
 | 
			
		||||
		lib,
 | 
			
		||||
		nil,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return app
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *ExtApplication) run() {
 | 
			
		||||
	// Set the "eth" api on to the containers context
 | 
			
		||||
	context := app.container.Engine().Context()
 | 
			
		||||
	context.SetVar("eth", app)
 | 
			
		||||
	context.SetVar("ui", app.lib)
 | 
			
		||||
 | 
			
		||||
	err := app.container.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the main loop
 | 
			
		||||
	go app.mainLoop()
 | 
			
		||||
 | 
			
		||||
	// Subscribe to events
 | 
			
		||||
	reactor := app.lib.eth.Reactor()
 | 
			
		||||
	reactor.Subscribe("newBlock", app.blockChan)
 | 
			
		||||
 | 
			
		||||
	app.container.NewWatcher(app.watcherQuitChan)
 | 
			
		||||
 | 
			
		||||
	win := app.container.Window()
 | 
			
		||||
	win.Show()
 | 
			
		||||
	win.Wait()
 | 
			
		||||
 | 
			
		||||
	app.stop()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *ExtApplication) stop() {
 | 
			
		||||
	// Clean up
 | 
			
		||||
	reactor := app.lib.eth.Reactor()
 | 
			
		||||
	reactor.Unsubscribe("newBlock", app.blockChan)
 | 
			
		||||
	for _, event := range app.registeredEvents {
 | 
			
		||||
		reactor.Unsubscribe(event, app.changeChan)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Kill the main loop
 | 
			
		||||
	app.quitChan <- true
 | 
			
		||||
	app.watcherQuitChan <- true
 | 
			
		||||
 | 
			
		||||
	close(app.blockChan)
 | 
			
		||||
	close(app.quitChan)
 | 
			
		||||
	close(app.changeChan)
 | 
			
		||||
 | 
			
		||||
	app.container.Destroy()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *ExtApplication) mainLoop() {
 | 
			
		||||
out:
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-app.quitChan:
 | 
			
		||||
			break out
 | 
			
		||||
		case block := <-app.blockChan:
 | 
			
		||||
			if block, ok := block.Resource.(*ethchain.Block); ok {
 | 
			
		||||
				app.container.NewBlock(block)
 | 
			
		||||
			}
 | 
			
		||||
		case object := <-app.changeChan:
 | 
			
		||||
			if stateObject, ok := object.Resource.(*ethchain.StateObject); ok {
 | 
			
		||||
				app.container.ObjectChanged(stateObject)
 | 
			
		||||
			} else if storageObject, ok := object.Resource.(*ethchain.StorageState); ok {
 | 
			
		||||
				app.container.StorageChanged(storageObject)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *ExtApplication) Watch(addr, storageAddr string) {
 | 
			
		||||
	var event string
 | 
			
		||||
	if len(storageAddr) == 0 {
 | 
			
		||||
		event = "object:" + string(ethutil.Hex2Bytes(addr))
 | 
			
		||||
		app.lib.eth.Reactor().Subscribe(event, app.changeChan)
 | 
			
		||||
	} else {
 | 
			
		||||
		event = "storage:" + string(ethutil.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr))
 | 
			
		||||
		app.lib.eth.Reactor().Subscribe(event, app.changeChan)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app.registeredEvents = append(app.registeredEvents, event)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										405
									
								
								ethereal/ui/gui.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,405 @@
 | 
			
		||||
package ethui
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ethereum/eth-go"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethchain"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethdb"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethlog"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethpub"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/utils"
 | 
			
		||||
	"github.com/go-qml/qml"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var logger = ethlog.NewLogger("GUI")
 | 
			
		||||
 | 
			
		||||
type Gui struct {
 | 
			
		||||
	// The main application window
 | 
			
		||||
	win *qml.Window
 | 
			
		||||
	// QML Engine
 | 
			
		||||
	engine    *qml.Engine
 | 
			
		||||
	component *qml.Common
 | 
			
		||||
	// The ethereum interface
 | 
			
		||||
	eth *eth.Ethereum
 | 
			
		||||
 | 
			
		||||
	// The public Ethereum library
 | 
			
		||||
	uiLib *UiLib
 | 
			
		||||
 | 
			
		||||
	txDb *ethdb.LDBDatabase
 | 
			
		||||
 | 
			
		||||
	pub      *ethpub.PEthereum
 | 
			
		||||
	logLevel ethlog.LogLevel
 | 
			
		||||
	open     bool
 | 
			
		||||
 | 
			
		||||
	Session string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create GUI, but doesn't start it
 | 
			
		||||
func New(ethereum *eth.Ethereum, session string, logLevel int) *Gui {
 | 
			
		||||
 | 
			
		||||
	db, err := ethdb.NewLDBDatabase("tx_database")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pub := ethpub.NewPEthereum(ethereum)
 | 
			
		||||
 | 
			
		||||
	return &Gui{eth: ethereum, txDb: db, pub: pub, logLevel: ethlog.LogLevel(logLevel), Session: session, open: false}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) Start(assetPath string) {
 | 
			
		||||
	const version = "0.5.0 RC15"
 | 
			
		||||
 | 
			
		||||
	defer gui.txDb.Close()
 | 
			
		||||
 | 
			
		||||
	// Register ethereum functions
 | 
			
		||||
	qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{
 | 
			
		||||
		Init: func(p *ethpub.PBlock, obj qml.Object) { p.Number = 0; p.Hash = "" },
 | 
			
		||||
	}, {
 | 
			
		||||
		Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
 | 
			
		||||
	}, {
 | 
			
		||||
		Init: func(p *ethpub.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" },
 | 
			
		||||
	}})
 | 
			
		||||
 | 
			
		||||
	ethutil.Config.SetClientString("Ethereal")
 | 
			
		||||
 | 
			
		||||
	// Create a new QML engine
 | 
			
		||||
	gui.engine = qml.NewEngine()
 | 
			
		||||
	context := gui.engine.Context()
 | 
			
		||||
 | 
			
		||||
	// Expose the eth library and the ui library to QML
 | 
			
		||||
	context.SetVar("eth", gui)
 | 
			
		||||
	context.SetVar("pub", gui.pub)
 | 
			
		||||
	gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath)
 | 
			
		||||
	context.SetVar("ui", gui.uiLib)
 | 
			
		||||
 | 
			
		||||
	// Load the main QML interface
 | 
			
		||||
	data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
 | 
			
		||||
 | 
			
		||||
	var win *qml.Window
 | 
			
		||||
	var err error
 | 
			
		||||
	var addlog = false
 | 
			
		||||
	if len(data) == 0 {
 | 
			
		||||
		win, err = gui.showKeyImport(context)
 | 
			
		||||
	} else {
 | 
			
		||||
		win, err = gui.showWallet(context)
 | 
			
		||||
		addlog = true
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorln("asset not found: you can set an alternative asset path on the command line using option 'asset_path'", err)
 | 
			
		||||
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logger.Infoln("Starting GUI")
 | 
			
		||||
	gui.open = true
 | 
			
		||||
	win.Show()
 | 
			
		||||
	// only add the gui logger after window is shown otherwise slider wont be shown
 | 
			
		||||
	if addlog {
 | 
			
		||||
		ethlog.AddLogSystem(gui)
 | 
			
		||||
	}
 | 
			
		||||
	win.Wait()
 | 
			
		||||
	// need to silence gui logger after window closed otherwise logsystem hangs
 | 
			
		||||
	gui.SetLogLevel(ethlog.Silence)
 | 
			
		||||
	gui.open = false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) Stop() {
 | 
			
		||||
	if gui.open {
 | 
			
		||||
		gui.SetLogLevel(ethlog.Silence)
 | 
			
		||||
		gui.open = false
 | 
			
		||||
		gui.win.Hide()
 | 
			
		||||
	}
 | 
			
		||||
	logger.Infoln("Stopped")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) ToggleMining() {
 | 
			
		||||
	var txt string
 | 
			
		||||
	if gui.eth.Mining {
 | 
			
		||||
		utils.StopMining(gui.eth)
 | 
			
		||||
		txt = "Start mining"
 | 
			
		||||
	} else {
 | 
			
		||||
		utils.StartMining(gui.eth)
 | 
			
		||||
		txt = "Stop mining"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gui.win.Root().Set("miningButtonText", txt)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	win := gui.createWindow(component)
 | 
			
		||||
 | 
			
		||||
	gui.setInitialBlockChain()
 | 
			
		||||
	gui.loadAddressBook()
 | 
			
		||||
	gui.readPreviousTransactions()
 | 
			
		||||
	gui.setPeerInfo()
 | 
			
		||||
 | 
			
		||||
	go gui.update()
 | 
			
		||||
 | 
			
		||||
	return win, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
 | 
			
		||||
	context.SetVar("lib", gui)
 | 
			
		||||
	component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/first_run.qml"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return gui.createWindow(component), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
 | 
			
		||||
	win := comp.CreateWindow(nil)
 | 
			
		||||
 | 
			
		||||
	gui.win = win
 | 
			
		||||
	gui.uiLib.win = win
 | 
			
		||||
 | 
			
		||||
	return gui.win
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) ImportAndSetPrivKey(secret string) bool {
 | 
			
		||||
	err := gui.eth.KeyManager().InitFromString(gui.Session, 0, secret)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorln("unable to import: ", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	logger.Errorln("successfully imported: ", err)
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) CreateAndSetPrivKey() (string, string, string, string) {
 | 
			
		||||
	err := gui.eth.KeyManager().Init(gui.Session, 0, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorln("unable to create key: ", err)
 | 
			
		||||
		return "", "", "", ""
 | 
			
		||||
	}
 | 
			
		||||
	return gui.eth.KeyManager().KeyPair().AsStrings()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) setInitialBlockChain() {
 | 
			
		||||
	sBlk := gui.eth.BlockChain().LastBlockHash
 | 
			
		||||
	blk := gui.eth.BlockChain().GetBlock(sBlk)
 | 
			
		||||
	for ; blk != nil; blk = gui.eth.BlockChain().GetBlock(sBlk) {
 | 
			
		||||
		sBlk = blk.PrevHash
 | 
			
		||||
		addr := gui.address()
 | 
			
		||||
 | 
			
		||||
		// Loop through all transactions to see if we missed any while being offline
 | 
			
		||||
		for _, tx := range blk.Transactions() {
 | 
			
		||||
			if bytes.Compare(tx.Sender(), addr) == 0 || bytes.Compare(tx.Recipient, addr) == 0 {
 | 
			
		||||
				if ok, _ := gui.txDb.Get(tx.Hash()); ok == nil {
 | 
			
		||||
					gui.txDb.Put(tx.Hash(), tx.RlpEncode())
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		gui.processBlock(blk, true)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type address struct {
 | 
			
		||||
	Name, Address string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var namereg = ethutil.Hex2Bytes("bb5f186604d057c1c5240ca2ae0f6430138ac010")
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) loadAddressBook() {
 | 
			
		||||
	gui.win.Root().Call("clearAddress")
 | 
			
		||||
	stateObject := gui.eth.StateManager().CurrentState().GetStateObject(namereg)
 | 
			
		||||
	if stateObject != nil {
 | 
			
		||||
		stateObject.State().EachStorage(func(name string, value *ethutil.Value) {
 | 
			
		||||
			gui.win.Root().Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())})
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) readPreviousTransactions() {
 | 
			
		||||
	it := gui.txDb.Db().NewIterator(nil, nil)
 | 
			
		||||
	addr := gui.address()
 | 
			
		||||
	for it.Next() {
 | 
			
		||||
		tx := ethchain.NewTransactionFromBytes(it.Value())
 | 
			
		||||
 | 
			
		||||
		var inout string
 | 
			
		||||
		if bytes.Compare(tx.Sender(), addr) == 0 {
 | 
			
		||||
			inout = "send"
 | 
			
		||||
		} else {
 | 
			
		||||
			inout = "recv"
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		gui.win.Root().Call("addTx", ethpub.NewPTx(tx), inout)
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	it.Release()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) processBlock(block *ethchain.Block, initial bool) {
 | 
			
		||||
	gui.win.Root().Call("addBlock", ethpub.NewPBlock(block), initial)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
 | 
			
		||||
	var str string
 | 
			
		||||
	if unconfirmedFunds != nil {
 | 
			
		||||
		pos := "+"
 | 
			
		||||
		if unconfirmedFunds.Cmp(big.NewInt(0)) < 0 {
 | 
			
		||||
			pos = "-"
 | 
			
		||||
		}
 | 
			
		||||
		val := ethutil.CurrencyToString(new(big.Int).Abs(ethutil.BigCopy(unconfirmedFunds)))
 | 
			
		||||
		str = fmt.Sprintf("%v (%s %v)", ethutil.CurrencyToString(amount), pos, val)
 | 
			
		||||
	} else {
 | 
			
		||||
		str = fmt.Sprintf("%v", ethutil.CurrencyToString(amount))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gui.win.Root().Call("setWalletValue", str)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Simple go routine function that updates the list of peers in the GUI
 | 
			
		||||
func (gui *Gui) update() {
 | 
			
		||||
	reactor := gui.eth.Reactor()
 | 
			
		||||
 | 
			
		||||
	blockChan := make(chan ethutil.React, 1)
 | 
			
		||||
	txChan := make(chan ethutil.React, 1)
 | 
			
		||||
	objectChan := make(chan ethutil.React, 1)
 | 
			
		||||
	peerChan := make(chan ethutil.React, 1)
 | 
			
		||||
 | 
			
		||||
	reactor.Subscribe("newBlock", blockChan)
 | 
			
		||||
	reactor.Subscribe("newTx:pre", txChan)
 | 
			
		||||
	reactor.Subscribe("newTx:post", txChan)
 | 
			
		||||
	reactor.Subscribe("object:"+string(namereg), objectChan)
 | 
			
		||||
	reactor.Subscribe("peerList", peerChan)
 | 
			
		||||
 | 
			
		||||
	ticker := time.NewTicker(5 * time.Second)
 | 
			
		||||
 | 
			
		||||
	state := gui.eth.StateManager().TransState()
 | 
			
		||||
 | 
			
		||||
	unconfirmedFunds := new(big.Int)
 | 
			
		||||
	gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Amount)))
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case b := <-blockChan:
 | 
			
		||||
			block := b.Resource.(*ethchain.Block)
 | 
			
		||||
			gui.processBlock(block, false)
 | 
			
		||||
			if bytes.Compare(block.Coinbase, gui.address()) == 0 {
 | 
			
		||||
				gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.address()).Amount, nil)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case txMsg := <-txChan:
 | 
			
		||||
			tx := txMsg.Resource.(*ethchain.Transaction)
 | 
			
		||||
 | 
			
		||||
			if txMsg.Event == "newTx:pre" {
 | 
			
		||||
				object := state.GetAccount(gui.address())
 | 
			
		||||
 | 
			
		||||
				if bytes.Compare(tx.Sender(), gui.address()) == 0 {
 | 
			
		||||
					gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "send")
 | 
			
		||||
					gui.txDb.Put(tx.Hash(), tx.RlpEncode())
 | 
			
		||||
 | 
			
		||||
					unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
 | 
			
		||||
				} else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
 | 
			
		||||
					gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "recv")
 | 
			
		||||
					gui.txDb.Put(tx.Hash(), tx.RlpEncode())
 | 
			
		||||
 | 
			
		||||
					unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				gui.setWalletValue(object.Amount, unconfirmedFunds)
 | 
			
		||||
			} else {
 | 
			
		||||
				object := state.GetAccount(gui.address())
 | 
			
		||||
				if bytes.Compare(tx.Sender(), gui.address()) == 0 {
 | 
			
		||||
					object.SubAmount(tx.Value)
 | 
			
		||||
				} else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
 | 
			
		||||
					object.AddAmount(tx.Value)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				gui.setWalletValue(object.Amount, nil)
 | 
			
		||||
 | 
			
		||||
				state.UpdateStateObject(object)
 | 
			
		||||
			}
 | 
			
		||||
		case <-objectChan:
 | 
			
		||||
			gui.loadAddressBook()
 | 
			
		||||
		case <-peerChan:
 | 
			
		||||
			gui.setPeerInfo()
 | 
			
		||||
		case <-ticker.C:
 | 
			
		||||
			gui.setPeerInfo()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) setPeerInfo() {
 | 
			
		||||
	gui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", gui.eth.PeerCount(), gui.eth.MaxPeers))
 | 
			
		||||
 | 
			
		||||
	gui.win.Root().Call("resetPeers")
 | 
			
		||||
	for _, peer := range gui.pub.GetPeers() {
 | 
			
		||||
		gui.win.Root().Call("addPeer", peer)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) privateKey() string {
 | 
			
		||||
	return ethutil.Bytes2Hex(gui.eth.KeyManager().PrivateKey())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) address() []byte {
 | 
			
		||||
	return gui.eth.KeyManager().Address()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) RegisterName(name string) {
 | 
			
		||||
	name = fmt.Sprintf("\"%s\"\n1", name)
 | 
			
		||||
	gui.pub.Transact(gui.privateKey(), "namereg", "1000", "1000000", "150", name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
 | 
			
		||||
	return gui.pub.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
 | 
			
		||||
	return gui.pub.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) ChangeClientId(id string) {
 | 
			
		||||
	ethutil.Config.SetIdentifier(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) ClientId() string {
 | 
			
		||||
	return ethutil.Config.Identifier
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// functions that allow Gui to implement interface ethlog.LogSystem
 | 
			
		||||
func (gui *Gui) SetLogLevel(level ethlog.LogLevel) {
 | 
			
		||||
	gui.logLevel = level
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) GetLogLevel() ethlog.LogLevel {
 | 
			
		||||
	return gui.logLevel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// this extra function needed to give int typecast value to gui widget
 | 
			
		||||
// that sets initial loglevel to default
 | 
			
		||||
func (gui *Gui) GetLogLevelInt() int {
 | 
			
		||||
	return int(gui.logLevel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) Println(v ...interface{}) {
 | 
			
		||||
	gui.printLog(fmt.Sprintln(v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (gui *Gui) Printf(format string, v ...interface{}) {
 | 
			
		||||
	gui.printLog(fmt.Sprintf(format, v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Print function that logs directly to the GUI
 | 
			
		||||
func (gui *Gui) printLog(s string) {
 | 
			
		||||
	str := strings.TrimRight(s, "\n")
 | 
			
		||||
	lines := strings.Split(str, "\n")
 | 
			
		||||
	for _, line := range lines {
 | 
			
		||||
		gui.win.Root().Call("addLog", line)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										133
									
								
								ethereal/ui/html_container.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,133 @@
 | 
			
		||||
package ethui
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethchain"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethpub"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"github.com/go-qml/qml"
 | 
			
		||||
	"github.com/howeyc/fsnotify"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type HtmlApplication struct {
 | 
			
		||||
	win     *qml.Window
 | 
			
		||||
	webView qml.Object
 | 
			
		||||
	engine  *qml.Engine
 | 
			
		||||
	lib     *UiLib
 | 
			
		||||
	path    string
 | 
			
		||||
	watcher *fsnotify.Watcher
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHtmlApplication(path string, lib *UiLib) *HtmlApplication {
 | 
			
		||||
	engine := qml.NewEngine()
 | 
			
		||||
 | 
			
		||||
	return &HtmlApplication{engine: engine, lib: lib, path: path}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) Create() error {
 | 
			
		||||
	component, err := app.engine.LoadFile(app.lib.AssetPath("qml/webapp.qml"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if filepath.Ext(app.path) == "eth" {
 | 
			
		||||
		return errors.New("Ethereum package not yet supported")
 | 
			
		||||
 | 
			
		||||
		// TODO
 | 
			
		||||
		ethutil.OpenPackage(app.path)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	win := component.CreateWindow(nil)
 | 
			
		||||
	win.Set("url", app.path)
 | 
			
		||||
	webView := win.ObjectByName("webView")
 | 
			
		||||
 | 
			
		||||
	app.win = win
 | 
			
		||||
	app.webView = webView
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) RootFolder() string {
 | 
			
		||||
	folder, err := url.Parse(app.path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return path.Dir(folder.RequestURI())
 | 
			
		||||
}
 | 
			
		||||
func (app *HtmlApplication) RecursiveFolders() []os.FileInfo {
 | 
			
		||||
	files, _ := ioutil.ReadDir(app.RootFolder())
 | 
			
		||||
	var folders []os.FileInfo
 | 
			
		||||
	for _, file := range files {
 | 
			
		||||
		if file.IsDir() {
 | 
			
		||||
			folders = append(folders, file)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return folders
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) NewWatcher(quitChan chan bool) {
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	app.watcher, err = fsnotify.NewWatcher()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	err = app.watcher.Watch(app.RootFolder())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	for _, folder := range app.RecursiveFolders() {
 | 
			
		||||
		fullPath := app.RootFolder() + "/" + folder.Name()
 | 
			
		||||
		app.watcher.Watch(fullPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
	out:
 | 
			
		||||
		for {
 | 
			
		||||
			select {
 | 
			
		||||
			case <-quitChan:
 | 
			
		||||
				app.watcher.Close()
 | 
			
		||||
				break out
 | 
			
		||||
			case <-app.watcher.Event:
 | 
			
		||||
				//logger.Debugln("Got event:", ev)
 | 
			
		||||
				app.webView.Call("reload")
 | 
			
		||||
			case err := <-app.watcher.Error:
 | 
			
		||||
				// TODO: Do something here
 | 
			
		||||
				logger.Infoln("Watcher error:", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) Engine() *qml.Engine {
 | 
			
		||||
	return app.engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) Window() *qml.Window {
 | 
			
		||||
	return app.win
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) NewBlock(block *ethchain.Block) {
 | 
			
		||||
	b := ðpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
 | 
			
		||||
	app.webView.Call("onNewBlockCb", b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) ObjectChanged(stateObject *ethchain.StateObject) {
 | 
			
		||||
	app.webView.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) StorageChanged(storageObject *ethchain.StorageState) {
 | 
			
		||||
	app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *HtmlApplication) Destroy() {
 | 
			
		||||
	app.engine.Destroy()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								ethereal/ui/qml_app.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,59 @@
 | 
			
		||||
package ethui
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/ethereum/eth-go/ethchain"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethpub"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"github.com/go-qml/qml"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type QmlApplication struct {
 | 
			
		||||
	win    *qml.Window
 | 
			
		||||
	engine *qml.Engine
 | 
			
		||||
	lib    *UiLib
 | 
			
		||||
	path   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQmlApplication(path string, lib *UiLib) *QmlApplication {
 | 
			
		||||
	engine := qml.NewEngine()
 | 
			
		||||
	return &QmlApplication{engine: engine, path: path, lib: lib}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *QmlApplication) Create() error {
 | 
			
		||||
	component, err := app.engine.LoadFile(app.path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Warnln(err)
 | 
			
		||||
	}
 | 
			
		||||
	app.win = component.CreateWindow(nil)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *QmlApplication) Destroy() {
 | 
			
		||||
	app.engine.Destroy()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *QmlApplication) NewWatcher(quitChan chan bool) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Events
 | 
			
		||||
func (app *QmlApplication) NewBlock(block *ethchain.Block) {
 | 
			
		||||
	pblock := ðpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
 | 
			
		||||
	app.win.Call("onNewBlockCb", pblock)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *QmlApplication) ObjectChanged(stateObject *ethchain.StateObject) {
 | 
			
		||||
	app.win.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (app *QmlApplication) StorageChanged(storageObject *ethchain.StorageState) {
 | 
			
		||||
	app.win.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Getters
 | 
			
		||||
func (app *QmlApplication) Engine() *qml.Engine {
 | 
			
		||||
	return app.engine
 | 
			
		||||
}
 | 
			
		||||
func (app *QmlApplication) Window() *qml.Window {
 | 
			
		||||
	return app.win
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										100
									
								
								ethereal/ui/ui_lib.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,100 @@
 | 
			
		||||
package ethui
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/ethereum/eth-go"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"github.com/go-qml/qml"
 | 
			
		||||
	"path"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type memAddr struct {
 | 
			
		||||
	Num   string
 | 
			
		||||
	Value string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UI Library that has some basic functionality exposed
 | 
			
		||||
type UiLib struct {
 | 
			
		||||
	engine    *qml.Engine
 | 
			
		||||
	eth       *eth.Ethereum
 | 
			
		||||
	connected bool
 | 
			
		||||
	assetPath string
 | 
			
		||||
	// The main application window
 | 
			
		||||
	win      *qml.Window
 | 
			
		||||
	Db       *Debugger
 | 
			
		||||
	DbWindow *DebuggerWindow
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
 | 
			
		||||
	return &UiLib{engine: engine, eth: eth, assetPath: assetPath}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ui *UiLib) OpenQml(path string) {
 | 
			
		||||
	container := NewQmlApplication(path[7:], ui)
 | 
			
		||||
	app := NewExtApplication(container, ui)
 | 
			
		||||
 | 
			
		||||
	go app.run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ui *UiLib) OpenHtml(path string) {
 | 
			
		||||
	container := NewHtmlApplication(path, ui)
 | 
			
		||||
	app := NewExtApplication(container, ui)
 | 
			
		||||
 | 
			
		||||
	go app.run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ui *UiLib) Muted(content string) {
 | 
			
		||||
	component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Debugln(err)
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	win := component.CreateWindow(nil)
 | 
			
		||||
	go func() {
 | 
			
		||||
		path := "file://" + ui.AssetPath("muted/index.html")
 | 
			
		||||
		win.Set("url", path)
 | 
			
		||||
 | 
			
		||||
		win.Show()
 | 
			
		||||
		win.Wait()
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ui *UiLib) Connect(button qml.Object) {
 | 
			
		||||
	if !ui.connected {
 | 
			
		||||
		ui.eth.Start(true)
 | 
			
		||||
		ui.connected = true
 | 
			
		||||
		button.Set("enabled", false)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ui *UiLib) ConnectToPeer(addr string) {
 | 
			
		||||
	ui.eth.ConnectToPeer(addr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ui *UiLib) AssetPath(p string) string {
 | 
			
		||||
	return path.Join(ui.assetPath, p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
 | 
			
		||||
	dbWindow := NewDebuggerWindow(self)
 | 
			
		||||
	object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.Hex2Bytes(contractHash))
 | 
			
		||||
	if len(object.Script()) > 0 {
 | 
			
		||||
		dbWindow.SetCode("0x" + ethutil.Bytes2Hex(object.Script()))
 | 
			
		||||
	}
 | 
			
		||||
	dbWindow.SetData("0x" + data)
 | 
			
		||||
 | 
			
		||||
	dbWindow.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *UiLib) StartDbWithCode(code string) {
 | 
			
		||||
	dbWindow := NewDebuggerWindow(self)
 | 
			
		||||
	dbWindow.SetCode("0x" + code)
 | 
			
		||||
	dbWindow.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *UiLib) StartDebugger() {
 | 
			
		||||
	dbWindow := NewDebuggerWindow(self)
 | 
			
		||||
	//self.DbWindow = dbWindow
 | 
			
		||||
 | 
			
		||||
	dbWindow.Show()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								ethereum/cmd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,32 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/ethereum/eth-go"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/utils"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitJsConsole(ethereum *eth.Ethereum) {
 | 
			
		||||
	repl := NewJSRepl(ethereum)
 | 
			
		||||
	go repl.Start()
 | 
			
		||||
	utils.RegisterInterrupt(func(os.Signal) {
 | 
			
		||||
		repl.Stop()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ExecJsFile(ethereum *eth.Ethereum, InputFile string) {
 | 
			
		||||
	file, err := os.Open(InputFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
	content, err := ioutil.ReadAll(file)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Fatalln(err)
 | 
			
		||||
	}
 | 
			
		||||
	re := NewJSRE(ethereum)
 | 
			
		||||
	utils.RegisterInterrupt(func(os.Signal) {
 | 
			
		||||
		re.Stop()
 | 
			
		||||
	})
 | 
			
		||||
	re.Run(string(content))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										76
									
								
								ethereum/flags.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,76 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethlog"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/user"
 | 
			
		||||
	"path"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var Identifier string
 | 
			
		||||
var KeyRing string
 | 
			
		||||
var KeyStore string
 | 
			
		||||
var StartRpc bool
 | 
			
		||||
var RpcPort int
 | 
			
		||||
var UseUPnP bool
 | 
			
		||||
var OutboundPort string
 | 
			
		||||
var ShowGenesis bool
 | 
			
		||||
var AddPeer string
 | 
			
		||||
var MaxPeer int
 | 
			
		||||
var GenAddr bool
 | 
			
		||||
var UseSeed bool
 | 
			
		||||
var SecretFile string
 | 
			
		||||
var ExportDir string
 | 
			
		||||
var NonInteractive bool
 | 
			
		||||
var Datadir string
 | 
			
		||||
var LogFile string
 | 
			
		||||
var ConfigFile string
 | 
			
		||||
var DebugFile string
 | 
			
		||||
var LogLevel int
 | 
			
		||||
 | 
			
		||||
// flags specific to cli client
 | 
			
		||||
var StartMining bool
 | 
			
		||||
var StartJsConsole bool
 | 
			
		||||
var InputFile string
 | 
			
		||||
 | 
			
		||||
func defaultDataDir() string {
 | 
			
		||||
	usr, _ := user.Current()
 | 
			
		||||
	return path.Join(usr.HomeDir, ".ethereum")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
 | 
			
		||||
 | 
			
		||||
func Init() {
 | 
			
		||||
	flag.Usage = func() {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0])
 | 
			
		||||
		flag.PrintDefaults()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flag.StringVar(&Identifier, "id", "", "Custom client identifier")
 | 
			
		||||
	flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
 | 
			
		||||
	flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)")
 | 
			
		||||
	flag.StringVar(&OutboundPort, "port", "30303", "listening port")
 | 
			
		||||
	flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
 | 
			
		||||
	flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
 | 
			
		||||
	flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
 | 
			
		||||
	flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
 | 
			
		||||
	flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
 | 
			
		||||
	flag.BoolVar(&UseSeed, "seed", true, "seed peers")
 | 
			
		||||
	flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
 | 
			
		||||
	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(&ConfigFile, "conf", defaultConfigFile, "config file")
 | 
			
		||||
	flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
 | 
			
		||||
	flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
 | 
			
		||||
 | 
			
		||||
	flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
 | 
			
		||||
	flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")
 | 
			
		||||
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	InputFile = flag.Arg(0)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										231
									
								
								ethereum/javascript_runtime.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,231 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ethereum/eth-go"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethchain"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethlog"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethpub"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/utils"
 | 
			
		||||
	"github.com/obscuren/otto"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var jsrelogger = ethlog.NewLogger("JSRE")
 | 
			
		||||
 | 
			
		||||
type JSRE struct {
 | 
			
		||||
	ethereum *eth.Ethereum
 | 
			
		||||
	vm       *otto.Otto
 | 
			
		||||
	lib      *ethpub.PEthereum
 | 
			
		||||
 | 
			
		||||
	blockChan  chan ethutil.React
 | 
			
		||||
	changeChan chan ethutil.React
 | 
			
		||||
	quitChan   chan bool
 | 
			
		||||
 | 
			
		||||
	objectCb map[string][]otto.Value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (jsre *JSRE) LoadExtFile(path string) {
 | 
			
		||||
	result, err := ioutil.ReadFile(path)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		jsre.vm.Run(result)
 | 
			
		||||
	} else {
 | 
			
		||||
		jsrelogger.Debugln("Could not load file:", path)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (jsre *JSRE) LoadIntFile(file string) {
 | 
			
		||||
	assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal", "assets", "ext")
 | 
			
		||||
	jsre.LoadExtFile(path.Join(assetPath, file))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewJSRE(ethereum *eth.Ethereum) *JSRE {
 | 
			
		||||
	re := &JSRE{
 | 
			
		||||
		ethereum,
 | 
			
		||||
		otto.New(),
 | 
			
		||||
		ethpub.NewPEthereum(ethereum),
 | 
			
		||||
		make(chan ethutil.React, 1),
 | 
			
		||||
		make(chan ethutil.React, 1),
 | 
			
		||||
		make(chan bool),
 | 
			
		||||
		make(map[string][]otto.Value),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Init the JS lib
 | 
			
		||||
	re.vm.Run(jsLib)
 | 
			
		||||
 | 
			
		||||
	// Load extra javascript files
 | 
			
		||||
	re.LoadIntFile("string.js")
 | 
			
		||||
	re.LoadIntFile("big.js")
 | 
			
		||||
 | 
			
		||||
	// We have to make sure that, whoever calls this, calls "Stop"
 | 
			
		||||
	go re.mainLoop()
 | 
			
		||||
 | 
			
		||||
	re.Bind("eth", &JSEthereum{re.lib, re.vm})
 | 
			
		||||
 | 
			
		||||
	re.initStdFuncs()
 | 
			
		||||
 | 
			
		||||
	jsrelogger.Infoln("started")
 | 
			
		||||
 | 
			
		||||
	return re
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) Bind(name string, v interface{}) {
 | 
			
		||||
	self.vm.Set(name, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) Run(code string) (otto.Value, error) {
 | 
			
		||||
	return self.vm.Run(code)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) Require(file string) error {
 | 
			
		||||
	if len(filepath.Ext(file)) == 0 {
 | 
			
		||||
		file += ".js"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fh, err := os.Open(file)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	content, _ := ioutil.ReadAll(fh)
 | 
			
		||||
	self.Run("exports = {};(function() {" + string(content) + "})();")
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) Stop() {
 | 
			
		||||
	// Kill the main loop
 | 
			
		||||
	self.quitChan <- true
 | 
			
		||||
 | 
			
		||||
	close(self.blockChan)
 | 
			
		||||
	close(self.quitChan)
 | 
			
		||||
	close(self.changeChan)
 | 
			
		||||
	jsrelogger.Infoln("stopped")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) mainLoop() {
 | 
			
		||||
	// Subscribe to events
 | 
			
		||||
	reactor := self.ethereum.Reactor()
 | 
			
		||||
	reactor.Subscribe("newBlock", self.blockChan)
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-self.quitChan:
 | 
			
		||||
			break out
 | 
			
		||||
		case block := <-self.blockChan:
 | 
			
		||||
			if _, ok := block.Resource.(*ethchain.Block); ok {
 | 
			
		||||
			}
 | 
			
		||||
		case object := <-self.changeChan:
 | 
			
		||||
			if stateObject, ok := object.Resource.(*ethchain.StateObject); ok {
 | 
			
		||||
				for _, cb := range self.objectCb[ethutil.Bytes2Hex(stateObject.Address())] {
 | 
			
		||||
					val, _ := self.vm.ToValue(ethpub.NewPStateObject(stateObject))
 | 
			
		||||
					cb.Call(cb, val)
 | 
			
		||||
				}
 | 
			
		||||
			} else if storageObject, ok := object.Resource.(*ethchain.StorageState); ok {
 | 
			
		||||
				for _, cb := range self.objectCb[ethutil.Bytes2Hex(storageObject.StateAddress)+ethutil.Bytes2Hex(storageObject.Address)] {
 | 
			
		||||
					val, _ := self.vm.ToValue(ethpub.NewPStorageState(storageObject))
 | 
			
		||||
					cb.Call(cb, val)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) initStdFuncs() {
 | 
			
		||||
	t, _ := self.vm.Get("eth")
 | 
			
		||||
	eth := t.Object()
 | 
			
		||||
	eth.Set("watch", self.watch)
 | 
			
		||||
	eth.Set("addPeer", self.addPeer)
 | 
			
		||||
	eth.Set("require", self.require)
 | 
			
		||||
	eth.Set("stopMining", self.stopMining)
 | 
			
		||||
	eth.Set("startMining", self.startMining)
 | 
			
		||||
	eth.Set("execBlock", self.execBlock)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The following methods are natively implemented javascript functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) stopMining(call otto.FunctionCall) otto.Value {
 | 
			
		||||
	v, _ := self.vm.ToValue(utils.StopMining(self.ethereum))
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) startMining(call otto.FunctionCall) otto.Value {
 | 
			
		||||
	v, _ := self.vm.ToValue(utils.StartMining(self.ethereum))
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// eth.watch
 | 
			
		||||
func (self *JSRE) watch(call otto.FunctionCall) otto.Value {
 | 
			
		||||
	addr, _ := call.Argument(0).ToString()
 | 
			
		||||
	var storageAddr string
 | 
			
		||||
	var cb otto.Value
 | 
			
		||||
	var storageCallback bool
 | 
			
		||||
	if len(call.ArgumentList) > 2 {
 | 
			
		||||
		storageCallback = true
 | 
			
		||||
		storageAddr, _ = call.Argument(1).ToString()
 | 
			
		||||
		cb = call.Argument(2)
 | 
			
		||||
	} else {
 | 
			
		||||
		cb = call.Argument(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if storageCallback {
 | 
			
		||||
		self.objectCb[addr+storageAddr] = append(self.objectCb[addr+storageAddr], cb)
 | 
			
		||||
 | 
			
		||||
		event := "storage:" + string(ethutil.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr))
 | 
			
		||||
		self.ethereum.Reactor().Subscribe(event, self.changeChan)
 | 
			
		||||
	} else {
 | 
			
		||||
		self.objectCb[addr] = append(self.objectCb[addr], cb)
 | 
			
		||||
 | 
			
		||||
		event := "object:" + string(ethutil.Hex2Bytes(addr))
 | 
			
		||||
		self.ethereum.Reactor().Subscribe(event, self.changeChan)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return otto.UndefinedValue()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) addPeer(call otto.FunctionCall) otto.Value {
 | 
			
		||||
	host, err := call.Argument(0).ToString()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return otto.FalseValue()
 | 
			
		||||
	}
 | 
			
		||||
	self.ethereum.ConnectToPeer(host)
 | 
			
		||||
 | 
			
		||||
	return otto.TrueValue()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) require(call otto.FunctionCall) otto.Value {
 | 
			
		||||
	file, err := call.Argument(0).ToString()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return otto.UndefinedValue()
 | 
			
		||||
	}
 | 
			
		||||
	if err := self.Require(file); err != nil {
 | 
			
		||||
		fmt.Println("err:", err)
 | 
			
		||||
		return otto.UndefinedValue()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t, _ := self.vm.Get("exports")
 | 
			
		||||
 | 
			
		||||
	return t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRE) execBlock(call otto.FunctionCall) otto.Value {
 | 
			
		||||
	hash, err := call.Argument(0).ToString()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return otto.UndefinedValue()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = utils.BlockDo(self.ethereum, ethutil.Hex2Bytes(hash))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
		return otto.FalseValue()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return otto.TrueValue()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								ethereum/js_lib.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,53 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
const jsLib = `
 | 
			
		||||
function pp(object) {
 | 
			
		||||
    var str = "";
 | 
			
		||||
 | 
			
		||||
    if(object instanceof Array) {
 | 
			
		||||
        str += "[ ";
 | 
			
		||||
        for(var i = 0, l = object.length; i < l; i++) {
 | 
			
		||||
            str += pp(object[i]);
 | 
			
		||||
 | 
			
		||||
            if(i < l-1) {
 | 
			
		||||
                str += ", ";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        str += " ]";
 | 
			
		||||
    } else if(typeof(object) === "object") {
 | 
			
		||||
        str += "{ ";
 | 
			
		||||
        var last = Object.keys(object).sort().pop()
 | 
			
		||||
        for(var k in object) {
 | 
			
		||||
            str += k + ": " + pp(object[k]);
 | 
			
		||||
 | 
			
		||||
            if(k !== last) {
 | 
			
		||||
                str += ", ";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        str += " }";
 | 
			
		||||
    } else if(typeof(object) === "string") {
 | 
			
		||||
        str += "\033[32m'" + object + "'";
 | 
			
		||||
    } else if(typeof(object) === "undefined") {
 | 
			
		||||
        str += "\033[1m\033[30m" + object;
 | 
			
		||||
    } else if(typeof(object) === "number") {
 | 
			
		||||
        str += "\033[31m" + object;
 | 
			
		||||
    } else if(typeof(object) === "function") {
 | 
			
		||||
	str += "\033[35m[Function]";
 | 
			
		||||
    } else {
 | 
			
		||||
        str += object;                    
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    str += "\033[0m";
 | 
			
		||||
 | 
			
		||||
    return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function prettyPrint(/* */) {
 | 
			
		||||
    var args = arguments;
 | 
			
		||||
    for(var i = 0, l = args.length; i < l; i++) {
 | 
			
		||||
	    console.log(pp(args[i]))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var print = prettyPrint;
 | 
			
		||||
`
 | 
			
		||||
							
								
								
									
										57
									
								
								ethereum/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,57 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/ethereum/eth-go/ethlog"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/utils"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var logger = ethlog.NewLogger("CLI")
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	runtime.GOMAXPROCS(runtime.NumCPU())
 | 
			
		||||
 | 
			
		||||
	utils.HandleInterrupt()
 | 
			
		||||
 | 
			
		||||
	// precedence: code-internal flag default < config file < environment variables < command line
 | 
			
		||||
	Init() // parsing command line
 | 
			
		||||
	utils.InitConfig(ConfigFile, Datadir, Identifier, "ETH")
 | 
			
		||||
 | 
			
		||||
	utils.InitDataDir(Datadir)
 | 
			
		||||
 | 
			
		||||
	utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile)
 | 
			
		||||
 | 
			
		||||
	db := utils.NewDatabase()
 | 
			
		||||
 | 
			
		||||
	keyManager := utils.NewKeyManager(KeyStore, Datadir, db)
 | 
			
		||||
 | 
			
		||||
	// create, import, export keys
 | 
			
		||||
	utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
 | 
			
		||||
 | 
			
		||||
	ethereum := utils.NewEthereum(db, keyManager, UseUPnP, OutboundPort, MaxPeer)
 | 
			
		||||
 | 
			
		||||
	if ShowGenesis {
 | 
			
		||||
		utils.ShowGenesis(ethereum)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if StartMining {
 | 
			
		||||
		utils.StartMining(ethereum)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// better reworked as cases
 | 
			
		||||
	if StartJsConsole {
 | 
			
		||||
		InitJsConsole(ethereum)
 | 
			
		||||
	} else if len(InputFile) > 0 {
 | 
			
		||||
		ExecJsFile(ethereum, InputFile)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if StartRpc {
 | 
			
		||||
		utils.StartRpc(ethereum, RpcPort)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	utils.StartEthereum(ethereum, UseSeed)
 | 
			
		||||
 | 
			
		||||
	// this blocks the thread
 | 
			
		||||
	ethereum.WaitForShutdown()
 | 
			
		||||
	ethlog.Flush()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										153
									
								
								ethereum/repl.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,153 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ethereum/eth-go"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethpub"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"github.com/obscuren/otto"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Repl interface {
 | 
			
		||||
	Start()
 | 
			
		||||
	Stop()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type JSRepl struct {
 | 
			
		||||
	re *JSRE
 | 
			
		||||
 | 
			
		||||
	prompt string
 | 
			
		||||
 | 
			
		||||
	history *os.File
 | 
			
		||||
 | 
			
		||||
	running bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
 | 
			
		||||
	hist, err := os.OpenFile(path.Join(ethutil.Config.ExecPath, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &JSRepl{re: NewJSRE(ethereum), prompt: "> ", history: hist}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRepl) Start() {
 | 
			
		||||
	if !self.running {
 | 
			
		||||
		self.running = true
 | 
			
		||||
		logger.Infoln("init JS Console")
 | 
			
		||||
		reader := bufio.NewReader(self.history)
 | 
			
		||||
		for {
 | 
			
		||||
			line, err := reader.ReadString('\n')
 | 
			
		||||
			if err != nil && err == io.EOF {
 | 
			
		||||
				break
 | 
			
		||||
			} else if err != nil {
 | 
			
		||||
				fmt.Println("error reading history", err)
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			addHistory(line[:len(line)-1])
 | 
			
		||||
		}
 | 
			
		||||
		self.read()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRepl) Stop() {
 | 
			
		||||
	if self.running {
 | 
			
		||||
		self.running = false
 | 
			
		||||
		self.re.Stop()
 | 
			
		||||
		logger.Infoln("exit JS Console")
 | 
			
		||||
		self.history.Close()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRepl) parseInput(code string) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if r := recover(); r != nil {
 | 
			
		||||
			fmt.Println("[native] error", r)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	value, err := self.re.Run(code)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	self.PrintValue(value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The JSEthereum object attempts to wrap the PEthereum object and returns
 | 
			
		||||
// meaningful javascript objects
 | 
			
		||||
type JSBlock struct {
 | 
			
		||||
	*ethpub.PBlock
 | 
			
		||||
	eth *JSEthereum
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSBlock) GetTransaction(hash string) otto.Value {
 | 
			
		||||
	return self.eth.toVal(self.PBlock.GetTransaction(hash))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type JSEthereum struct {
 | 
			
		||||
	*ethpub.PEthereum
 | 
			
		||||
	vm *otto.Otto
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSEthereum) GetBlock(hash string) otto.Value {
 | 
			
		||||
	return self.toVal(&JSBlock{self.PEthereum.GetBlock(hash), self})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSEthereum) GetPeers() otto.Value {
 | 
			
		||||
	return self.toVal(self.PEthereum.GetPeers())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSEthereum) GetKey() otto.Value {
 | 
			
		||||
	return self.toVal(self.PEthereum.GetKey())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSEthereum) GetStateObject(addr string) otto.Value {
 | 
			
		||||
	return self.toVal(self.PEthereum.GetStateObject(addr))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSEthereum) GetStateKeyVals(addr string) otto.Value {
 | 
			
		||||
	return self.toVal(self.PEthereum.GetStateObject(addr).StateKeyVal(false))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value {
 | 
			
		||||
	r, err := self.PEthereum.Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
 | 
			
		||||
		return otto.UndefinedValue()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return self.toVal(r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSEthereum) Create(key, valueStr, gasStr, gasPriceStr, scriptStr string) otto.Value {
 | 
			
		||||
	r, err := self.PEthereum.Create(key, valueStr, gasStr, gasPriceStr, scriptStr)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
 | 
			
		||||
		return otto.UndefinedValue()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return self.toVal(r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSEthereum) toVal(v interface{}) otto.Value {
 | 
			
		||||
	result, err := self.vm.ToValue(v)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("Value unknown:", err)
 | 
			
		||||
 | 
			
		||||
		return otto.UndefinedValue()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										123
									
								
								ethereum/repl_darwin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,123 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include
 | 
			
		||||
// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib
 | 
			
		||||
// #cgo LDFLAGS: -lreadline
 | 
			
		||||
// #include <stdio.h>
 | 
			
		||||
// #include <stdlib.h>
 | 
			
		||||
// #include <readline/readline.h>
 | 
			
		||||
// #include <readline/history.h>
 | 
			
		||||
import "C"
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/signal"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func initReadLine() {
 | 
			
		||||
	C.rl_catch_sigwinch = 0
 | 
			
		||||
	C.rl_catch_signals = 0
 | 
			
		||||
	c := make(chan os.Signal, 1)
 | 
			
		||||
	signal.Notify(c, syscall.SIGWINCH)
 | 
			
		||||
	signal.Notify(c, os.Interrupt)
 | 
			
		||||
	go func() {
 | 
			
		||||
		for sig := range c {
 | 
			
		||||
			switch sig {
 | 
			
		||||
			case syscall.SIGWINCH:
 | 
			
		||||
				C.rl_resize_terminal()
 | 
			
		||||
 | 
			
		||||
			case os.Interrupt:
 | 
			
		||||
				C.rl_cleanup_after_signal()
 | 
			
		||||
			default:
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func readLine(prompt *string) *string {
 | 
			
		||||
	var p *C.char
 | 
			
		||||
 | 
			
		||||
	//readline allows an empty prompt(NULL)
 | 
			
		||||
	if prompt != nil {
 | 
			
		||||
		p = C.CString(*prompt)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret := C.readline(p)
 | 
			
		||||
 | 
			
		||||
	if p != nil {
 | 
			
		||||
		C.free(unsafe.Pointer(p))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ret == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	} //EOF
 | 
			
		||||
 | 
			
		||||
	s := C.GoString(ret)
 | 
			
		||||
	C.free(unsafe.Pointer(ret))
 | 
			
		||||
	return &s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addHistory(s string) {
 | 
			
		||||
	p := C.CString(s)
 | 
			
		||||
	C.add_history(p)
 | 
			
		||||
	C.free(unsafe.Pointer(p))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var indentCount = 0
 | 
			
		||||
var str = ""
 | 
			
		||||
 | 
			
		||||
func (self *JSRepl) setIndent() {
 | 
			
		||||
	open := strings.Count(str, "{")
 | 
			
		||||
	open += strings.Count(str, "(")
 | 
			
		||||
	closed := strings.Count(str, "}")
 | 
			
		||||
	closed += strings.Count(str, ")")
 | 
			
		||||
	indentCount = open - closed
 | 
			
		||||
	if indentCount <= 0 {
 | 
			
		||||
		self.prompt = "> "
 | 
			
		||||
	} else {
 | 
			
		||||
		self.prompt = strings.Join(make([]string, indentCount*2), "..")
 | 
			
		||||
		self.prompt += " "
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRepl) read() {
 | 
			
		||||
	initReadLine()
 | 
			
		||||
L:
 | 
			
		||||
	for {
 | 
			
		||||
		switch result := readLine(&self.prompt); true {
 | 
			
		||||
		case result == nil:
 | 
			
		||||
			break L
 | 
			
		||||
 | 
			
		||||
		case *result != "":
 | 
			
		||||
			str += *result + "\n"
 | 
			
		||||
 | 
			
		||||
			self.setIndent()
 | 
			
		||||
 | 
			
		||||
			if indentCount <= 0 {
 | 
			
		||||
				if *result == "exit" {
 | 
			
		||||
					self.Stop()
 | 
			
		||||
					break L
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				hist := str[:len(str)-1]
 | 
			
		||||
				addHistory(hist) //allow user to recall this line
 | 
			
		||||
				self.history.WriteString(str)
 | 
			
		||||
 | 
			
		||||
				self.parseInput(str)
 | 
			
		||||
 | 
			
		||||
				str = ""
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRepl) PrintValue(v interface{}) {
 | 
			
		||||
	method, _ := self.re.vm.Get("prettyPrint")
 | 
			
		||||
	v, err := self.re.vm.ToValue(v)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		method.Call(method, v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								ethereum/repl_linux.go
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
repl_darwin.go
 | 
			
		||||
							
								
								
									
										24
									
								
								ethereum/repl_windows.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,24 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (self *JSRepl) read() {
 | 
			
		||||
	reader := bufio.NewReader(os.Stdin)
 | 
			
		||||
	for {
 | 
			
		||||
		fmt.Printf(self.prompt)
 | 
			
		||||
		str, _, err := reader.ReadLine()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println("Error reading input", err)
 | 
			
		||||
		} else {
 | 
			
		||||
			self.parseInput(string(str))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *JSRepl) PrintValue(value otto.Value) {
 | 
			
		||||
	fmt.Println(value)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								install.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@@ -0,0 +1,57 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
if [ "$1" == "" ]; then
 | 
			
		||||
	echo "Usage $0 executable branch ethereum develop"
 | 
			
		||||
	echo "executable    ethereum or ethereal"
 | 
			
		||||
	echo "branch        develop or master"
 | 
			
		||||
	exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
exe=$1
 | 
			
		||||
branch=$2
 | 
			
		||||
 | 
			
		||||
# Test if go is installed
 | 
			
		||||
command -v go >/dev/null 2>&1 || { echo >&2 "Unable to find 'go'. This script requires go."; exit 1; }
 | 
			
		||||
 | 
			
		||||
# Test if $GOPATH is set
 | 
			
		||||
if [ "$GOPATH" == "" ]; then
 | 
			
		||||
	echo "\$GOPATH not set"
 | 
			
		||||
	exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo "go get -u -d github.com/ethereum/go-ethereum/$exe"
 | 
			
		||||
go get -v -u -d github.com/ethereum/go-ethereum/$exe
 | 
			
		||||
if [ $? != 0 ]; then
 | 
			
		||||
	echo "go get failed"
 | 
			
		||||
	exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo "serpent-go"
 | 
			
		||||
cd $GOPATH/src/github.com/obscuren/serpent-go
 | 
			
		||||
 | 
			
		||||
echo "init submodule"
 | 
			
		||||
git submodule init
 | 
			
		||||
git submodule update
 | 
			
		||||
 | 
			
		||||
echo "eth-go"
 | 
			
		||||
cd $GOPATH/src/github.com/ethereum/eth-go
 | 
			
		||||
git checkout $branch
 | 
			
		||||
 | 
			
		||||
echo "go-ethereum"
 | 
			
		||||
cd $GOPATH/src/github.com/ethereum/go-ethereum/$exe
 | 
			
		||||
git checkout $branch
 | 
			
		||||
 | 
			
		||||
if [ "$exe" == "ethereal" ]; then
 | 
			
		||||
	echo "Building ethereal GUI. Assuming Qt is installed. If this step"
 | 
			
		||||
	echo "fails; please refer to: https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)"
 | 
			
		||||
else
 | 
			
		||||
	echo "Building ethereum CLI."
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
go install
 | 
			
		||||
if [ $? == 0 ]; then
 | 
			
		||||
	echo "go install failed"
 | 
			
		||||
	exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo "done. Please run $exe :-)"
 | 
			
		||||
							
								
								
									
										253
									
								
								utils/cmd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,253 @@
 | 
			
		||||
package utils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/ethereum/eth-go"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethcrypto"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethdb"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethlog"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethminer"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethpub"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethrpc"
 | 
			
		||||
	"github.com/ethereum/eth-go/ethutil"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/signal"
 | 
			
		||||
	"path"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var logger = ethlog.NewLogger("CLI")
 | 
			
		||||
var interruptCallbacks = []func(os.Signal){}
 | 
			
		||||
 | 
			
		||||
// Register interrupt handlers callbacks
 | 
			
		||||
func RegisterInterrupt(cb func(os.Signal)) {
 | 
			
		||||
	interruptCallbacks = append(interruptCallbacks, cb)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// go routine that call interrupt handlers in order of registering
 | 
			
		||||
func HandleInterrupt() {
 | 
			
		||||
	c := make(chan os.Signal, 1)
 | 
			
		||||
	go func() {
 | 
			
		||||
		signal.Notify(c, os.Interrupt)
 | 
			
		||||
		for sig := range c {
 | 
			
		||||
			logger.Errorf("Shutting down (%v) ... \n", sig)
 | 
			
		||||
			RunInterruptCallbacks(sig)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunInterruptCallbacks(sig os.Signal) {
 | 
			
		||||
	for _, cb := range interruptCallbacks {
 | 
			
		||||
		cb(sig)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AbsolutePath(Datadir string, filename string) string {
 | 
			
		||||
	if path.IsAbs(filename) {
 | 
			
		||||
		return filename
 | 
			
		||||
	}
 | 
			
		||||
	return path.Join(Datadir, filename)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func openLogFile(Datadir string, filename string) *os.File {
 | 
			
		||||
	path := AbsolutePath(Datadir, filename)
 | 
			
		||||
	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
 | 
			
		||||
	}
 | 
			
		||||
	return file
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func confirm(message string) bool {
 | 
			
		||||
	fmt.Println(message, "Are you sure? (y/n)")
 | 
			
		||||
	var r string
 | 
			
		||||
	fmt.Scanln(&r)
 | 
			
		||||
	for ; ; fmt.Scanln(&r) {
 | 
			
		||||
		if r == "n" || r == "y" {
 | 
			
		||||
			break
 | 
			
		||||
		} else {
 | 
			
		||||
			fmt.Printf("Yes or no?", r)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return r == "y"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InitDataDir(Datadir string) {
 | 
			
		||||
	_, err := os.Stat(Datadir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			fmt.Printf("Data directory '%s' doesn't exist, creating it\n", Datadir)
 | 
			
		||||
			os.Mkdir(Datadir, 0777)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) {
 | 
			
		||||
	var writer io.Writer
 | 
			
		||||
	if LogFile == "" {
 | 
			
		||||
		writer = os.Stdout
 | 
			
		||||
	} else {
 | 
			
		||||
		writer = openLogFile(Datadir, LogFile)
 | 
			
		||||
	}
 | 
			
		||||
	ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.LogLevel(LogLevel)))
 | 
			
		||||
	if DebugFile != "" {
 | 
			
		||||
		writer = openLogFile(Datadir, DebugFile)
 | 
			
		||||
		ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.DebugLevel))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InitConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) {
 | 
			
		||||
	InitDataDir(Datadir)
 | 
			
		||||
	ethutil.ReadConfig(ConfigFile, Datadir, Identifier, EnvPrefix)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func exit(err error) {
 | 
			
		||||
	status := 0
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorln("Fatal: ", err)
 | 
			
		||||
		status = 1
 | 
			
		||||
	}
 | 
			
		||||
	ethlog.Flush()
 | 
			
		||||
	os.Exit(status)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewDatabase() ethutil.Database {
 | 
			
		||||
	db, err := ethdb.NewLDBDatabase("database")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		exit(err)
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewEthereum(db ethutil.Database, keyManager *ethcrypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
 | 
			
		||||
	ethereum, err := eth.New(db, keyManager, eth.CapDefault, usePnp)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Fatalln("eth start err:", err)
 | 
			
		||||
	}
 | 
			
		||||
	ethereum.Port = OutboundPort
 | 
			
		||||
	ethereum.MaxPeers = MaxPeer
 | 
			
		||||
	return ethereum
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
 | 
			
		||||
	logger.Infof("Starting Ethereum v%s", ethutil.Config.Ver)
 | 
			
		||||
	ethereum.Start(UseSeed)
 | 
			
		||||
	RegisterInterrupt(func(sig os.Signal) {
 | 
			
		||||
		ethereum.Stop()
 | 
			
		||||
		ethlog.Flush()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ShowGenesis(ethereum *eth.Ethereum) {
 | 
			
		||||
	logger.Infoln(ethereum.BlockChain().Genesis())
 | 
			
		||||
	exit(nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *ethcrypto.KeyManager {
 | 
			
		||||
	var keyManager *ethcrypto.KeyManager
 | 
			
		||||
	switch {
 | 
			
		||||
	case KeyStore == "db":
 | 
			
		||||
		keyManager = ethcrypto.NewDBKeyManager(db)
 | 
			
		||||
	case KeyStore == "file":
 | 
			
		||||
		keyManager = ethcrypto.NewFileKeyManager(Datadir)
 | 
			
		||||
	default:
 | 
			
		||||
		exit(fmt.Errorf("unknown keystore type: %s", KeyStore))
 | 
			
		||||
	}
 | 
			
		||||
	return keyManager
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
 | 
			
		||||
	var err error
 | 
			
		||||
	switch {
 | 
			
		||||
	case GenAddr:
 | 
			
		||||
		if NonInteractive || confirm("This action overwrites your old private key.") {
 | 
			
		||||
			err = keyManager.Init(KeyRing, 0, true)
 | 
			
		||||
		}
 | 
			
		||||
		exit(err)
 | 
			
		||||
	case len(SecretFile) > 0:
 | 
			
		||||
		if NonInteractive || confirm("This action overwrites your old private key.") {
 | 
			
		||||
			err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile)
 | 
			
		||||
		}
 | 
			
		||||
		exit(err)
 | 
			
		||||
	case len(ExportDir) > 0:
 | 
			
		||||
		err = keyManager.Init(KeyRing, 0, false)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			err = keyManager.Export(ExportDir)
 | 
			
		||||
		}
 | 
			
		||||
		exit(err)
 | 
			
		||||
	default:
 | 
			
		||||
		// Creates a keypair if none exists
 | 
			
		||||
		err = keyManager.Init(KeyRing, 0, false)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			exit(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
 | 
			
		||||
	var err error
 | 
			
		||||
	ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
 | 
			
		||||
	} else {
 | 
			
		||||
		go ethereum.RpcServer.Start()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var miner ethminer.Miner
 | 
			
		||||
 | 
			
		||||
func StartMining(ethereum *eth.Ethereum) bool {
 | 
			
		||||
	if !ethereum.Mining {
 | 
			
		||||
		ethereum.Mining = true
 | 
			
		||||
 | 
			
		||||
		addr := ethereum.KeyManager().Address()
 | 
			
		||||
 | 
			
		||||
		go func() {
 | 
			
		||||
			miner = ethminer.NewDefaultMiner(addr, ethereum)
 | 
			
		||||
			// Give it some time to connect with peers
 | 
			
		||||
			time.Sleep(3 * time.Second)
 | 
			
		||||
			for !ethereum.IsUpToDate() == false {
 | 
			
		||||
				time.Sleep(5 * time.Second)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			logger.Infoln("Miner started")
 | 
			
		||||
			miner := ethminer.NewDefaultMiner(addr, ethereum)
 | 
			
		||||
			miner.Start()
 | 
			
		||||
		}()
 | 
			
		||||
		RegisterInterrupt(func(os.Signal) {
 | 
			
		||||
			StopMining(ethereum)
 | 
			
		||||
		})
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func StopMining(ethereum *eth.Ethereum) bool {
 | 
			
		||||
	if ethereum.Mining {
 | 
			
		||||
		miner.Stop()
 | 
			
		||||
		logger.Infoln("Miner stopped")
 | 
			
		||||
		ethereum.Mining = false
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Replay block
 | 
			
		||||
func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
 | 
			
		||||
	block := ethereum.BlockChain().GetBlock(hash)
 | 
			
		||||
	if block == nil {
 | 
			
		||||
		return fmt.Errorf("unknown block %x", hash)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	parent := ethereum.BlockChain().GetBlock(block.PrevHash)
 | 
			
		||||
 | 
			
		||||
	_, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||