Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
5f28013f
Commit
5f28013f
authored
May 30, 2014
by
obscuren
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop'
parents
f0f20500
65c5a20e
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1001 additions
and
1042 deletions
+1001
-1042
README.md
README.md
+7
-5
debugger.qml
ethereal/assets/debugger/debugger.qml
+8
-4
wallet.qml
ethereal/assets/qml/wallet.qml
+901
-1000
config.go
ethereal/config.go
+10
-13
ethereum.go
ethereal/ethereum.go
+17
-4
debugger.go
ethereal/ui/debugger.go
+2
-0
gui.go
ethereal/ui/gui.go
+47
-3
config.go
ethereum/config.go
+8
-10
ethereum.go
ethereum/ethereum.go
+1
-1
cmd.go
utils/cmd.go
+0
-2
No files found.
README.md
View file @
5f28013f
...
@@ -27,20 +27,22 @@ General command line options
...
@@ -27,20 +27,22 @@ General command line options
```
```
Shared between ethereum and ethereal
Shared between ethereum and ethereal
-m Start mining blocks
-id Set the custom identifier of the client (shows up on other clients)
-genaddr Generates a new address and private key (destructive action)
-port Port on which the server will accept incomming connections
-p Port on which the server will accept incomming connections
-upnp Enable UPnP
-upnp Enable UPnP
-x Desired amount of peers
-maxpeer Desired amount of peers
-r Start JSON RPC
-rpc Start JSON RPC
-dir Data directory used to store configs and databases
-dir Data directory used to store configs and databases
-import Import a private key
-import Import a private key
-genaddr Generates a new address and private key (destructive action)
-h This
-h This
Ethereum only
Ethereum only
ethereum [options] [filename]
ethereum [options] [filename]
-js Start the JavaScript REPL
-js Start the JavaScript REPL
filename Load the given file and interpret as JavaScript
filename Load the given file and interpret as JavaScript
-m Start mining blocks
Etheral only
Etheral only
-asset_path absolute path to GUI assets directory
-asset_path absolute path to GUI assets directory
...
...
ethereal/assets/debugger/debugger.qml
View file @
5f28013f
...
@@ -8,7 +8,7 @@ import Ethereum 1.0
...
@@ -8,7 +8,7 @@ import Ethereum 1.0
ApplicationWindow
{
ApplicationWindow
{
visible
:
false
visible
:
false
title
:
"IceC
ream
"
title
:
"IceC
REAM
"
minimumWidth
:
1280
minimumWidth
:
1280
minimumHeight
:
900
minimumHeight
:
900
width
:
1290
width
:
1290
...
@@ -224,8 +224,8 @@ ApplicationWindow {
...
@@ -224,8 +224,8 @@ ApplicationWindow {
}
}
function
setInstruction
(
num
)
{
function
setInstruction
(
num
)
{
asmTableView
.
selection
.
clear
()
//
asmTableView.selection.clear()
asmTableView
.
selection
.
select
(
num
)
//
asmTableView.selection.select(num)
}
}
function
setMem
(
mem
)
{
function
setMem
(
mem
)
{
...
@@ -255,6 +255,10 @@ ApplicationWindow {
...
@@ -255,6 +255,10 @@ ApplicationWindow {
}
}
function
setLog
(
msg
)
{
function
setLog
(
msg
)
{
logModel
.
append
({
message
:
msg
})
logModel
.
insert
(
0
,
{
message
:
msg
})
}
function
clearLog
()
{
logModel
.
clear
()
}
}
}
}
ethereal/assets/qml/wallet.qml
View file @
5f28013f
...
@@ -10,6 +10,8 @@ import Ethereum 1.0
...
@@ -10,6 +10,8 @@ import Ethereum 1.0
ApplicationWindow
{
ApplicationWindow
{
id
:
root
id
:
root
property
alias
miningButtonText
:
miningButton
.
text
width
:
900
width
:
900
height
:
600
height
:
600
minimumHeight
:
300
minimumHeight
:
300
...
@@ -27,13 +29,6 @@ ApplicationWindow {
...
@@ -27,13 +29,6 @@ ApplicationWindow {
}
}
Menu
{
Menu
{
title
:
"Tools"
MenuItem
{
text
:
"Muted"
shortcut
:
"Ctrl+e"
onTriggered
:
ui
.
muted
(
""
)
}
MenuItem
{
MenuItem
{
text
:
"Debugger"
text
:
"Debugger"
shortcut
:
"Ctrl+d"
shortcut
:
"Ctrl+d"
...
@@ -50,11 +45,6 @@ ApplicationWindow {
...
@@ -50,11 +45,6 @@ ApplicationWindow {
addPeerWin
.
visible
=
true
addPeerWin
.
visible
=
true
}
}
}
}
MenuItem
{
text
:
"Start"
onTriggered
:
ui
.
connect
()
}
}
}
Menu
{
Menu
{
...
@@ -180,6 +170,7 @@ ApplicationWindow {
...
@@ -180,6 +170,7 @@ ApplicationWindow {
visible
:
false
visible
:
false
anchors.fill
:
parent
anchors.fill
:
parent
color
:
"#00000000"
color
:
"#00000000"
/*
TabView{
TabView{
anchors.fill: parent
anchors.fill: parent
anchors.rightMargin: 5
anchors.rightMargin: 5
...
@@ -192,6 +183,10 @@ ApplicationWindow {
...
@@ -192,6 +183,10 @@ ApplicationWindow {
addTab("Contracts", newContract)
addTab("Contracts", newContract)
}
}
}
}
*/
Component.onCompleted
:
{
newContract
.
createObject
(
newTxView
)
}
}
}
Rectangle
{
Rectangle
{
...
@@ -204,7 +199,7 @@ ApplicationWindow {
...
@@ -204,7 +199,7 @@ ApplicationWindow {
id
:
blockTable
id
:
blockTable
width
:
parent
.
width
width
:
parent
.
width
anchors.top
:
parent
.
top
anchors.top
:
parent
.
top
anchors.bottom
:
logView
.
top
anchors.bottom
:
parent
.
bottom
TableViewColumn
{
role
:
"number"
;
title
:
"#"
;
width
:
100
}
TableViewColumn
{
role
:
"number"
;
title
:
"#"
;
width
:
100
}
TableViewColumn
{
role
:
"hash"
;
title
:
"Hash"
;
width
:
560
}
TableViewColumn
{
role
:
"hash"
;
title
:
"Hash"
;
width
:
560
}
TableViewColumn
{
role
:
"txAmount"
;
title
:
"Tx amount"
;
width
:
100
}
TableViewColumn
{
role
:
"txAmount"
;
title
:
"Tx amount"
;
width
:
100
}
...
@@ -217,19 +212,6 @@ ApplicationWindow {
...
@@ -217,19 +212,6 @@ ApplicationWindow {
}
}
}
}
property
var
logModel
:
ListModel
{
id
:
logModel
}
TableView
{
id
:
logView
width
:
parent
.
width
height
:
150
anchors.bottom
:
parent
.
bottom
TableViewColumn
{
role
:
"description"
;
title
:
"log"
}
model
:
logModel
}
}
}
Rectangle
{
Rectangle
{
...
@@ -257,6 +239,35 @@ ApplicationWindow {
...
@@ -257,6 +239,35 @@ ApplicationWindow {
text
:
pub
.
getKey
().
address
text
:
pub
.
getKey
().
address
width
:
500
width
:
500
}
}
property
var
addressModel
:
ListModel
{
id
:
addressModel
}
TableView
{
id
:
addressView
width
:
parent
.
width
height
:
200
anchors.bottom
:
logView
.
top
TableViewColumn
{
role
:
"name"
;
title
:
"name"
}
TableViewColumn
{
role
:
"address"
;
title
:
"address"
;
width
:
300
}
model
:
addressModel
}
property
var
logModel
:
ListModel
{
id
:
logModel
}
TableView
{
id
:
logView
width
:
parent
.
width
height
:
200
anchors.bottom
:
parent
.
bottom
TableViewColumn
{
role
:
"description"
;
title
:
"log"
}
model
:
logModel
}
}
}
/*
/*
...
@@ -294,8 +305,15 @@ ApplicationWindow {
...
@@ -294,8 +305,15 @@ ApplicationWindow {
}
}
statusBar
:
StatusBar
{
statusBar
:
StatusBar
{
height
:
30
RowLayout
{
RowLayout
{
anchors.fill
:
parent
Button
{
id
:
miningButton
onClicked
:
{
eth
.
toggleMining
()
}
text
:
"Start Mining"
}
Button
{
Button
{
property
var
enabled
:
true
property
var
enabled
:
true
...
@@ -319,8 +337,10 @@ ApplicationWindow {
...
@@ -319,8 +337,10 @@ ApplicationWindow {
anchors.leftMargin
:
5
anchors.leftMargin
:
5
id
:
walletValueLabel
id
:
walletValueLabel
}
}
}
Label
{
Label
{
y
:
7
anchors.right
:
peerImage
.
left
anchors.right
:
peerImage
.
left
anchors.rightMargin
:
5
anchors.rightMargin
:
5
id
:
peerLabel
id
:
peerLabel
...
@@ -328,26 +348,26 @@ ApplicationWindow {
...
@@ -328,26 +348,26 @@ ApplicationWindow {
text
:
"0 / 0"
text
:
"0 / 0"
}
}
Image
{
Image
{
y
:
7
id
:
peerImage
id
:
peerImage
anchors.right
:
parent
.
right
anchors.right
:
parent
.
right
width
:
10
;
height
:
10
width
:
10
;
height
:
10
source
:
ui
.
assetPath
(
"network.png"
)
source
:
ui
.
assetPath
(
"network.png"
)
}
}
}
}
}
Window
{
Window
{
id
:
popup
id
:
popup
visible
:
false
visible
:
false
property
var
block
property
var
block
width
:
root
.
width
width
:
root
.
width
height
:
24
0
height
:
30
0
Component
{
Component
{
id
:
blockDetailsDelegate
id
:
blockDetailsDelegate
Rectangle
{
Rectangle
{
color
:
"#252525"
color
:
"#252525"
width
:
popup
.
width
width
:
popup
.
width
height
:
20
0
height
:
15
0
Column
{
Column
{
anchors.leftMargin
:
10
anchors.leftMargin
:
10
anchors.topMargin
:
5
anchors.topMargin
:
5
...
@@ -356,6 +376,7 @@ ApplicationWindow {
...
@@ -356,6 +376,7 @@ ApplicationWindow {
Text
{
text
:
'<h3>Block details</h3>'
;
color
:
"#F2F2F2"
}
Text
{
text
:
'<h3>Block details</h3>'
;
color
:
"#F2F2F2"
}
Text
{
text
:
'<b>Block number:</b> '
+
number
;
color
:
"#F2F2F2"
}
Text
{
text
:
'<b>Block number:</b> '
+
number
;
color
:
"#F2F2F2"
}
Text
{
text
:
'<b>Hash:</b> '
+
hash
;
color
:
"#F2F2F2"
}
Text
{
text
:
'<b>Hash:</b> '
+
hash
;
color
:
"#F2F2F2"
}
Text
{
text
:
'<b>Coinbase:</b> '
+
coinbase
;
color
:
"#F2F2F2"
}
Text
{
text
:
'<b>Block found at:</b> '
+
prettyTime
;
color
:
"#F2F2F2"
}
Text
{
text
:
'<b>Block found at:</b> '
+
prettyTime
;
color
:
"#F2F2F2"
}
}
}
}
}
...
@@ -364,7 +385,7 @@ ApplicationWindow {
...
@@ -364,7 +385,7 @@ ApplicationWindow {
model
:
singleBlock
model
:
singleBlock
delegate
:
blockDetailsDelegate
delegate
:
blockDetailsDelegate
anchors.top
:
parent
.
top
anchors.top
:
parent
.
top
height
:
7
0
height
:
10
0
anchors.leftMargin
:
20
anchors.leftMargin
:
20
id
:
listViewThing
id
:
listViewThing
Layout.maximumHeight
:
40
Layout.maximumHeight
:
40
...
@@ -389,7 +410,7 @@ ApplicationWindow {
...
@@ -389,7 +410,7 @@ ApplicationWindow {
if
(
tx
.
data
)
{
if
(
tx
.
data
)
{
popup
.
showContractData
(
tx
)
popup
.
showContractData
(
tx
)
}
else
{
}
else
{
popup
.
height
=
23
0
popup
.
height
=
44
0
}
}
}
}
}
}
...
@@ -403,7 +424,7 @@ ApplicationWindow {
...
@@ -403,7 +424,7 @@ ApplicationWindow {
contractLabel
.
text
=
"<h4> Transaction ran contract "
+
tx
.
address
+
"</h4>"
contractLabel
.
text
=
"<h4> Transaction ran contract "
+
tx
.
address
+
"</h4>"
contractData
.
text
=
tx
.
rawData
contractData
.
text
=
tx
.
rawData
}
}
popup
.
height
=
40
0
popup
.
height
=
54
0
}
}
Rectangle
{
Rectangle
{
...
@@ -455,7 +476,7 @@ ApplicationWindow {
...
@@ -455,7 +476,7 @@ ApplicationWindow {
}
}
function
setDetails
(
block
){
function
setDetails
(
block
){
singleBlock
.
set
(
0
,
block
)
singleBlock
.
set
(
0
,
block
)
popup
.
height
=
23
0
popup
.
height
=
30
0
transactionModel
.
clear
()
transactionModel
.
clear
()
if
(
block
.
txs
!=
undefined
){
if
(
block
.
txs
!=
undefined
){
for
(
var
i
=
0
;
i
<
block
.
txs
.
count
;
++
i
)
{
for
(
var
i
=
0
;
i
<
block
.
txs
.
count
;
++
i
)
{
...
@@ -529,126 +550,17 @@ ApplicationWindow {
...
@@ -529,126 +550,17 @@ ApplicationWindow {
font.pointSize
:
12
font.pointSize
:
12
text
:
"<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>"
text
:
"<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>"
}
}
}
ApplicationWindow
{
id
:
debugWindow
visible
:
false
title
:
"Debugger"
minimumWidth
:
600
minimumHeight
:
600
width
:
800
height
:
600
Item
{
id
:
keyHandler
focus
:
true
Keys.onPressed
:
{
if
(
event
.
key
==
Qt
.
Key_Space
)
{
ui
.
next
()
}
}
}
SplitView
{
anchors.fill
:
parent
property
var
asmModel
:
ListModel
{
id
:
asmModel
}
TableView
{
id
:
asmTableView
width
:
200
TableViewColumn
{
role
:
"value"
;
title
:
""
;
width
:
100
}
model
:
asmModel
}
}
Rectangle
{
anchors.left
:
asmTableView
.
right
anchors.right
:
parent
.
right
SplitView
{
orientation
:
Qt
.
Vertical
anchors.fill
:
parent
TableView
{
property
var
memModel
:
ListModel
{
id
:
memModel
}
height
:
parent
.
height
/
2
width
:
parent
.
width
TableViewColumn
{
id
:
mnumColmn
;
role
:
"num"
;
title
:
"#"
;
width
:
50
}
TableViewColumn
{
role
:
"value"
;
title
:
"Memory"
;
width
:
750
}
model
:
memModel
}
SplitView
{
orientation
:
Qt
.
Horizontal
id
:
debugSplitView
TableView
{
property
var
debuggerLog
:
ListModel
{
id
:
debuggerLog
}
TableViewColumn
{
role
:
"value"
;
title
:
"Debug messages"
}
model
:
debuggerLog
}
TableView
{
property
var
stackModel
:
ListModel
{
id
:
stackModel
}
height
:
parent
.
height
/
2
width
:
parent
.
width
TableViewColumn
{
role
:
"value"
;
title
:
"Stack"
;
width
:
debugSplitView
.
width
}
model
:
stackModel
}
}
}
}
}
statusBar
:
StatusBar
{
RowLayout
{
anchors.fill
:
parent
Button
{
property
var
enabled
:
true
id
:
debugNextButton
onClicked
:
{
ui
.
next
()
}
text
:
"Next"
}
}
}
}
function
setAsm
(
asm
)
{
asmModel
.
append
({
asm
:
asm
})
}
function
setInstruction
(
num
)
{
asmTableView
.
selection
.
clear
()
asmTableView
.
selection
.
select
(
num
-
1
)
}
function
clearAsm
()
{
asmModel
.
clear
()
}
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
){
function
addDebugMessage
(
message
){
console
.
log
(
"WOOP:"
)
debuggerLog
.
append
({
value
:
message
})
debuggerLog
.
append
({
value
:
message
})
}
}
function
clearStack
()
{
function
addAddress
(
address
)
{
stackModel
.
clear
()
addressModel
.
append
({
name
:
address
.
name
,
address
:
address
.
address
})
}
function
clearAddress
()
{
addressModel
.
clear
()
}
}
function
loadPlugin
(
name
)
{
function
loadPlugin
(
name
)
{
...
@@ -667,7 +579,14 @@ ApplicationWindow {
...
@@ -667,7 +579,14 @@ ApplicationWindow {
}
else
{
}
else
{
isContract
=
"No"
isContract
=
"No"
}
}
txModel
.
insert
(
0
,
{
inout
:
inout
,
hash
:
tx
.
hash
,
address
:
tx
.
address
,
value
:
tx
.
value
,
contract
:
isContract
})
var
address
;
if
(
inout
==
"recv"
)
{
address
=
tx
.
sender
;
}
else
{
address
=
tx
.
address
;
}
txModel
.
insert
(
0
,
{
inout
:
inout
,
hash
:
tx
.
hash
,
address
:
address
,
value
:
tx
.
value
,
contract
:
isContract
})
}
}
function
addBlock
(
block
,
initial
)
{
function
addBlock
(
block
,
initial
)
{
...
@@ -682,15 +601,15 @@ ApplicationWindow {
...
@@ -682,15 +601,15 @@ ApplicationWindow {
}
}
if
(
initial
){
if
(
initial
){
blockModel
.
append
({
number
:
block
.
number
,
hash
:
block
.
hash
,
txs
:
txs
,
txAmount
:
amount
,
time
:
block
.
time
,
prettyTime
:
convertToPretty
(
block
.
time
)})
blockModel
.
append
({
number
:
block
.
number
,
coinbase
:
block
.
coinbase
,
hash
:
block
.
hash
,
txs
:
txs
,
txAmount
:
amount
,
time
:
block
.
time
,
prettyTime
:
convertToPretty
(
block
.
time
)})
}
else
{
}
else
{
blockModel
.
insert
(
0
,
{
number
:
block
.
number
,
hash
:
block
.
hash
,
txs
:
txs
,
txAmount
:
amount
,
time
:
block
.
time
,
prettyTime
:
convertToPretty
(
block
.
time
)})
blockModel
.
insert
(
0
,
{
number
:
block
.
number
,
coinbase
:
block
.
coinbase
,
hash
:
block
.
hash
,
txs
:
txs
,
txAmount
:
amount
,
time
:
block
.
time
,
prettyTime
:
convertToPretty
(
block
.
time
)})
}
}
}
}
function
addLog
(
str
)
{
function
addLog
(
str
)
{
if
(
str
.
len
!=
0
)
{
if
(
str
.
len
!=
0
)
{
logModel
.
append
(
{
description
:
str
})
logModel
.
insert
(
0
,
{
description
:
str
})
}
}
}
}
...
@@ -718,6 +637,7 @@ ApplicationWindow {
...
@@ -718,6 +637,7 @@ ApplicationWindow {
id
:
newContract
id
:
newContract
Column
{
Column
{
id
:
mainContractColumn
id
:
mainContractColumn
anchors.fill
:
parent
function
contractFormReady
(){
function
contractFormReady
(){
if
(
codeView
.
text
.
length
>
0
&&
txValue
.
text
.
length
>
0
&&
txGas
.
text
.
length
>
0
&&
txGasPrice
.
length
>
0
)
{
if
(
codeView
.
text
.
length
>
0
&&
txValue
.
text
.
length
>
0
&&
txGas
.
text
.
length
>
0
&&
txGasPrice
.
length
>
0
)
{
txButton
.
state
=
"READY"
txButton
.
state
=
"READY"
...
@@ -739,6 +659,8 @@ ApplicationWindow {
...
@@ -739,6 +659,8 @@ ApplicationWindow {
PropertyChanges
{
target
:
codeView
;
visible
:
false
}
PropertyChanges
{
target
:
codeView
;
visible
:
false
}
PropertyChanges
{
target
:
txButton
;
visible
:
false
}
PropertyChanges
{
target
:
txButton
;
visible
:
false
}
PropertyChanges
{
target
:
txDataLabel
;
visible
:
false
}
PropertyChanges
{
target
:
txDataLabel
;
visible
:
false
}
PropertyChanges
{
target
:
atLabel
;
visible
:
false
}
PropertyChanges
{
target
:
txFuelRecipient
;
visible
:
false
}
PropertyChanges
{
target
:
txResult
;
visible
:
true
}
PropertyChanges
{
target
:
txResult
;
visible
:
true
}
PropertyChanges
{
target
:
txOutput
;
visible
:
true
}
PropertyChanges
{
target
:
txOutput
;
visible
:
true
}
...
@@ -765,82 +687,70 @@ ApplicationWindow {
...
@@ -765,82 +687,70 @@ ApplicationWindow {
anchors.leftMargin
:
5
anchors.leftMargin
:
5
anchors.topMargin
:
5
anchors.topMargin
:
5
TextField
{
id
:
txFuelRecipient
placeholderText
:
"Address / Name or empty for contract"
//validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width
:
400
}
TextField
{
TextField
{
id
:
txValue
id
:
txValue
width
:
200
width
:
222
placeholderText
:
"Amount"
placeholderText
:
"Amount"
validator
:
RegExpValidator
{
regExp
:
/
\d
*/
}
validator
:
RegExpValidator
{
regExp
:
/
\d
*/
}
onTextChanged
:
{
onTextChanged
:
{
contractFormReady
()
contractFormReady
()
}
}
}
}
RowLayout
{
TextField
{
TextField
{
id
:
txGas
id
:
txGas
width
:
20
0
width
:
5
0
validator
:
RegExpValidator
{
regExp
:
/
\d
*/
}
validator
:
RegExpValidator
{
regExp
:
/
\d
*/
}
placeholderText
:
"Gas"
placeholderText
:
"Gas"
text
:
"500"
/*
onTextChanged: {
onTextChanged: {
contractFormReady()
contractFormReady()
}
}
*/
}
Label
{
id
:
atLabel
text
:
"@"
}
}
TextField
{
TextField
{
id
:
txGasPrice
id
:
txGasPrice
width
:
200
width
:
200
placeholderText
:
"Gas price"
placeholderText
:
"Gas price"
text
:
"1000000"
validator
:
RegExpValidator
{
regExp
:
/
\d
*/
}
validator
:
RegExpValidator
{
regExp
:
/
\d
*/
}
/*
onTextChanged: {
onTextChanged: {
contractFormReady()
contractFormReady()
}
}
}
*/
Row
{
id
:
rowContract
ExclusiveGroup
{
id
:
contractTypeGroup
}
RadioButton
{
id
:
createContractRadio
text
:
"Create contract"
checked
:
true
exclusiveGroup
:
contractTypeGroup
onClicked
:
{
txFuelRecipient
.
visible
=
false
txDataLabel
.
text
=
"Contract code"
}
}
RadioButton
{
id
:
runContractRadio
text
:
"Run contract"
exclusiveGroup
:
contractTypeGroup
onClicked
:
{
txFuelRecipient
.
visible
=
true
txDataLabel
.
text
=
"Contract arguments"
}
}
}
}
}
Label
{
Label
{
id
:
txDataLabel
id
:
txDataLabel
text
:
"Contract code
"
text
:
"Data
"
}
}
TextArea
{
TextArea
{
id
:
codeView
id
:
codeView
height
:
300
height
:
300
anchors.topMargin
:
5
anchors.topMargin
:
5
Layout.fillWidth
:
true
width
:
400
width
:
parent
.
width
/
2
onTextChanged
:
{
onTextChanged
:
{
contractFormReady
()
contractFormReady
()
}
}
}
}
TextField
{
id
:
txFuelRecipient
placeholderText
:
"Contract address"
validator
:
RegExpValidator
{
regExp
:
/
[
a-f0-9
]{40}
/
}
visible
:
false
width
:
530
}
Button
{
Button
{
id
:
txButton
id
:
txButton
...
@@ -883,7 +793,7 @@ ApplicationWindow {
...
@@ -883,7 +793,7 @@ ApplicationWindow {
Button
{
Button
{
id
:
newTxButton
id
:
newTxButton
visible
:
false
visible
:
false
text
:
"Create an other contract
"
text
:
"Create a new transaction
"
onClicked
:
{
onClicked
:
{
this
.
visible
=
false
this
.
visible
=
false
txResult
.
text
=
""
txResult
.
text
=
""
...
@@ -891,15 +801,6 @@ ApplicationWindow {
...
@@ -891,15 +801,6 @@ ApplicationWindow {
mainContractColumn
.
state
=
"SETUP"
mainContractColumn
.
state
=
"SETUP"
}
}
}
}
Button
{
id
:
debugButton
text
:
"Debug"
onClicked
:
{
var
res
=
ui
.
debugTx
(
""
,
txValue
.
text
,
txGas
.
text
,
txGasPrice
.
text
,
codeView
.
text
)
debugWindow
.
visible
=
true
}
}
}
}
}
}
...
@@ -948,7 +849,7 @@ ApplicationWindow {
...
@@ -948,7 +849,7 @@ ApplicationWindow {
id
:
txSimpleRecipient
id
:
txSimpleRecipient
placeholderText
:
"Recipient address"
placeholderText
:
"Recipient address"
Layout.fillWidth
:
true
Layout.fillWidth
:
true
validator
:
RegExpValidator
{
regExp
:
/
[
a-f0-9
]{40}
/
}
//
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width
:
530
width
:
530
onTextChanged
:
{
checkFormState
()
}
onTextChanged
:
{
checkFormState
()
}
}
}
...
@@ -976,7 +877,7 @@ ApplicationWindow {
...
@@ -976,7 +877,7 @@ ApplicationWindow {
text
:
"Send"
text
:
"Send"
onClicked
:
{
onClicked
:
{
//this.enabled = false
//this.enabled = false
var
res
=
eth
.
transact
(
txSimpleRecipient
.
text
,
txSimpleValue
.
text
,
""
,
""
,
""
)
var
res
=
eth
.
transact
(
txSimpleRecipient
.
text
,
txSimpleValue
.
text
,
"500"
,
"1000000"
,
""
)
if
(
res
[
1
])
{
if
(
res
[
1
])
{
txSimpleResult
.
text
=
"There has been an error broadcasting your transaction:"
+
res
[
1
].
error
()
txSimpleResult
.
text
=
"There has been an error broadcasting your transaction:"
+
res
[
1
].
error
()
}
else
{
}
else
{
...
...
ethereal/config.go
View file @
5f28013f
...
@@ -5,8 +5,8 @@ import (
...
@@ -5,8 +5,8 @@ import (
)
)
var
Identifier
string
var
Identifier
string
var
StartConsole
bool
var
StartMining
bool
//
var StartMining bool
var
StartRpc
bool
var
StartRpc
bool
var
RpcPort
int
var
RpcPort
int
var
UseUPnP
bool
var
UseUPnP
bool
...
@@ -18,25 +18,22 @@ var GenAddr bool
...
@@ -18,25 +18,22 @@ var GenAddr bool
var
UseSeed
bool
var
UseSeed
bool
var
ImportKey
string
var
ImportKey
string
var
ExportKey
bool
var
ExportKey
bool
var
DataDir
string
var
AssetPath
string
var
AssetPath
string
func
Init
()
{
func
Init
()
{
flag
.
StringVar
(
&
Identifier
,
"i"
,
""
,
"Custom client identifier"
)
flag
.
StringVar
(
&
Identifier
,
"id"
,
""
,
"Custom client identifier"
)
flag
.
BoolVar
(
&
StartConsole
,
"c"
,
false
,
"debug and testing console"
)
flag
.
StringVar
(
&
OutboundPort
,
"port"
,
"30303"
,
"listening port"
)
flag
.
BoolVar
(
&
StartMining
,
"m"
,
false
,
"start dagger mining"
)
flag
.
BoolVar
(
&
StartRpc
,
"r"
,
false
,
"start rpc server"
)
flag
.
BoolVar
(
&
ShowGenesis
,
"g"
,
false
,
"prints genesis header and exits"
)
flag
.
BoolVar
(
&
UseUPnP
,
"upnp"
,
false
,
"enable UPnP support"
)
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
.
StringVar
(
&
AssetPath
,
"asset_path"
,
""
,
"absolute path to GUI assets directory"
)
flag
.
BoolVar
(
&
ShowGenesis
,
"genesis"
,
false
,
"prints genesis header and exits"
)
flag
.
BoolVar
(
&
UseSeed
,
"seed"
,
true
,
"seed peers"
)
flag
.
BoolVar
(
&
UseSeed
,
"seed"
,
true
,
"seed peers"
)
flag
.
BoolVar
(
&
GenAddr
,
"genaddr"
,
false
,
"create a new priv/pub key"
)
flag
.
BoolVar
(
&
GenAddr
,
"genaddr"
,
false
,
"create a new priv/pub key"
)
flag
.
BoolVar
(
&
ExportKey
,
"export"
,
false
,
"export private key"
)
flag
.
BoolVar
(
&
ExportKey
,
"export"
,
false
,
"export private key"
)
flag
.
IntVar
(
&
RpcPort
,
"rpcport"
,
8080
,
"port to start json-rpc server on"
)
flag
.
StringVar
(
&
OutboundPort
,
"p"
,
"30303"
,
"listening port"
)
flag
.
StringVar
(
&
DataDir
,
"dir"
,
".ethereal"
,
"ethereum data directory"
)
flag
.
StringVar
(
&
ImportKey
,
"import"
,
""
,
"imports the given private key (hex)"
)
flag
.
StringVar
(
&
ImportKey
,
"import"
,
""
,
"imports the given private key (hex)"
)
flag
.
IntVar
(
&
MaxPeer
,
"x"
,
10
,
"maximum desired peers"
)
flag
.
StringVar
(
&
AssetPath
,
"asset_path"
,
""
,
"absolute path to GUI assets directory"
)
flag
.
Parse
()
flag
.
Parse
()
}
}
ethereal/ethereum.go
View file @
5f28013f
...
@@ -8,9 +8,11 @@ import (
...
@@ -8,9 +8,11 @@ import (
"github.com/ethereum/go-ethereum/ethereal/ui"
"github.com/ethereum/go-ethereum/ethereal/ui"
"github.com/ethereum/go-ethereum/utils"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"github.com/go-qml/qml"
"github.com/rakyll/globalconf"
"log"
"log"
"os"
"os"
"os/signal"
"os/signal"
"path"
"runtime"
"runtime"
)
)
...
@@ -39,7 +41,16 @@ func main() {
...
@@ -39,7 +41,16 @@ func main() {
runtime
.
GOMAXPROCS
(
runtime
.
NumCPU
())
runtime
.
GOMAXPROCS
(
runtime
.
NumCPU
())
ethchain
.
InitFees
()
ethchain
.
InitFees
()
ethutil
.
ReadConfig
(
DataDir
,
ethutil
.
LogFile
|
ethutil
.
LogStd
,
Identifier
)
g
,
err
:=
globalconf
.
NewWithOptions
(
&
globalconf
.
Options
{
Filename
:
path
.
Join
(
ethutil
.
ApplicationFolder
(
".ethereal"
),
"conf.ini"
),
})
if
err
!=
nil
{
fmt
.
Println
(
err
)
}
else
{
g
.
ParseAll
()
}
ethutil
.
ReadConfig
(
".ethereal"
,
ethutil
.
LogFile
|
ethutil
.
LogStd
,
Identifier
)
// Instantiated a eth stack
// Instantiated a eth stack
ethereum
,
err
:=
eth
.
New
(
eth
.
CapDefault
,
UseUPnP
)
ethereum
,
err
:=
eth
.
New
(
eth
.
CapDefault
,
UseUPnP
)
...
@@ -108,9 +119,11 @@ save these words so you can restore your account later: %s
...
@@ -108,9 +119,11 @@ save these words so you can restore your account later: %s
os
.
Exit
(
0
)
os
.
Exit
(
0
)
}
}
/*
if StartMining {
if StartMining {
utils.DoMining(ethereum)
utils.DoMining(ethereum)
}
}
*/
if
StartRpc
{
if
StartRpc
{
utils
.
DoRpc
(
ethereum
,
RpcPort
)
utils
.
DoRpc
(
ethereum
,
RpcPort
)
...
...
ethereal/ui/debugger.go
View file @
5f28013f
...
@@ -71,6 +71,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
...
@@ -71,6 +71,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
var
err
error
var
err
error
script
:=
ethutil
.
StringToByteFunc
(
scriptStr
,
func
(
s
string
)
(
ret
[]
byte
)
{
script
:=
ethutil
.
StringToByteFunc
(
scriptStr
,
func
(
s
string
)
(
ret
[]
byte
)
{
ret
,
err
=
ethutil
.
Compile
(
s
)
ret
,
err
=
ethutil
.
Compile
(
s
)
fmt
.
Printf
(
"%x
\n
"
,
ret
)
return
return
})
})
...
@@ -82,6 +83,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
...
@@ -82,6 +83,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
dis
:=
ethchain
.
Disassemble
(
script
)
dis
:=
ethchain
.
Disassemble
(
script
)
self
.
win
.
Root
()
.
Call
(
"clearAsm"
)
self
.
win
.
Root
()
.
Call
(
"clearAsm"
)
self
.
win
.
Root
()
.
Call
(
"clearLog"
)
for
_
,
str
:=
range
dis
{
for
_
,
str
:=
range
dis
{
self
.
win
.
Root
()
.
Call
(
"setAsm"
,
str
)
self
.
win
.
Root
()
.
Call
(
"setAsm"
,
str
)
...
...
ethereal/ui/gui.go
View file @
5f28013f
...
@@ -8,6 +8,7 @@ import (
...
@@ -8,6 +8,7 @@ import (
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"github.com/go-qml/qml"
"math/big"
"math/big"
"strings"
"strings"
...
@@ -66,7 +67,6 @@ func (gui *Gui) Start(assetPath string) {
...
@@ -66,7 +67,6 @@ func (gui *Gui) Start(assetPath string) {
}})
}})
ethutil
.
Config
.
SetClientString
(
fmt
.
Sprintf
(
"/Ethereal v%s"
,
version
))
ethutil
.
Config
.
SetClientString
(
fmt
.
Sprintf
(
"/Ethereal v%s"
,
version
))
ethutil
.
Config
.
Log
.
Infoln
(
"[GUI] Starting GUI"
)
// Create a new QML engine
// Create a new QML engine
gui
.
engine
=
qml
.
NewEngine
()
gui
.
engine
=
qml
.
NewEngine
()
context
:=
gui
.
engine
.
Context
()
context
:=
gui
.
engine
.
Context
()
...
@@ -93,12 +93,28 @@ func (gui *Gui) Start(assetPath string) {
...
@@ -93,12 +93,28 @@ func (gui *Gui) Start(assetPath string) {
panic
(
err
)
panic
(
err
)
}
}
ethutil
.
Config
.
Log
.
AddLogSystem
(
gui
)
ethutil
.
Config
.
Log
.
Infoln
(
"[GUI] Starting GUI"
)
win
.
Show
()
win
.
Show
()
win
.
Wait
()
win
.
Wait
()
gui
.
eth
.
Stop
()
gui
.
eth
.
Stop
()
}
}
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
)
{
func
(
gui
*
Gui
)
showWallet
(
context
*
qml
.
Context
)
(
*
qml
.
Window
,
error
)
{
component
,
err
:=
gui
.
engine
.
LoadFile
(
gui
.
uiLib
.
AssetPath
(
"qml/wallet.qml"
))
component
,
err
:=
gui
.
engine
.
LoadFile
(
gui
.
uiLib
.
AssetPath
(
"qml/wallet.qml"
))
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -107,8 +123,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
...
@@ -107,8 +123,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
win
:=
gui
.
createWindow
(
component
)
win
:=
gui
.
createWindow
(
component
)
go
gui
.
setInitialBlockChain
()
gui
.
setInitialBlockChain
()
go
gui
.
readPreviousTransactions
()
gui
.
loadAddressBook
()
gui
.
readPreviousTransactions
()
gui
.
setPeerInfo
()
go
gui
.
update
()
go
gui
.
update
()
return
win
,
nil
return
win
,
nil
...
@@ -145,6 +164,19 @@ func (gui *Gui) setInitialBlockChain() {
...
@@ -145,6 +164,19 @@ func (gui *Gui) setInitialBlockChain() {
}
}
}
}
type
address
struct
{
Name
,
Address
string
}
var
namereg
=
ethutil
.
FromHex
(
"bb5f186604d057c1c5240ca2ae0f6430138ac010"
)
func
(
gui
*
Gui
)
loadAddressBook
()
{
gui
.
win
.
Root
()
.
Call
(
"clearAddress"
)
gui
.
eth
.
StateManager
()
.
CurrentState
()
.
GetStateObject
(
namereg
)
.
State
()
.
EachStorage
(
func
(
name
string
,
value
*
ethutil
.
Value
)
{
gui
.
win
.
Root
()
.
Call
(
"addAddress"
,
struct
{
Name
,
Address
string
}{
name
,
ethutil
.
Hex
(
value
.
Bytes
())})
})
}
func
(
gui
*
Gui
)
readPreviousTransactions
()
{
func
(
gui
*
Gui
)
readPreviousTransactions
()
{
it
:=
gui
.
txDb
.
Db
()
.
NewIterator
(
nil
,
nil
)
it
:=
gui
.
txDb
.
Db
()
.
NewIterator
(
nil
,
nil
)
for
it
.
Next
()
{
for
it
.
Next
()
{
...
@@ -189,10 +221,14 @@ func (gui *Gui) update() {
...
@@ -189,10 +221,14 @@ func (gui *Gui) update() {
blockChan
:=
make
(
chan
ethutil
.
React
,
1
)
blockChan
:=
make
(
chan
ethutil
.
React
,
1
)
txChan
:=
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
(
"newBlock"
,
blockChan
)
reactor
.
Subscribe
(
"newTx:pre"
,
txChan
)
reactor
.
Subscribe
(
"newTx:pre"
,
txChan
)
reactor
.
Subscribe
(
"newTx:post"
,
txChan
)
reactor
.
Subscribe
(
"newTx:post"
,
txChan
)
reactor
.
Subscribe
(
"object:"
+
string
(
namereg
),
objectChan
)
reactor
.
Subscribe
(
"peerList"
,
peerChan
)
state
:=
gui
.
eth
.
StateManager
()
.
TransState
()
state
:=
gui
.
eth
.
StateManager
()
.
TransState
()
...
@@ -239,10 +275,18 @@ func (gui *Gui) update() {
...
@@ -239,10 +275,18 @@ func (gui *Gui) update() {
state
.
UpdateStateObject
(
object
)
state
.
UpdateStateObject
(
object
)
}
}
case
<-
objectChan
:
gui
.
loadAddressBook
()
case
<-
peerChan
:
gui
.
setPeerInfo
()
}
}
}
}
}
}
func
(
gui
*
Gui
)
setPeerInfo
()
{
gui
.
win
.
Root
()
.
Call
(
"setPeers"
,
fmt
.
Sprintf
(
"%d / %d"
,
gui
.
eth
.
PeerCount
(),
gui
.
eth
.
MaxPeers
))
}
// Logging functions that log directly to the GUI interface
// Logging functions that log directly to the GUI interface
func
(
gui
*
Gui
)
Println
(
v
...
interface
{})
{
func
(
gui
*
Gui
)
Println
(
v
...
interface
{})
{
str
:=
strings
.
TrimRight
(
fmt
.
Sprintln
(
v
...
),
"
\n
"
)
str
:=
strings
.
TrimRight
(
fmt
.
Sprintln
(
v
...
),
"
\n
"
)
...
...
ethereum/config.go
View file @
5f28013f
...
@@ -20,7 +20,6 @@ var UseSeed bool
...
@@ -20,7 +20,6 @@ var UseSeed bool
var
ImportKey
string
var
ImportKey
string
var
ExportKey
bool
var
ExportKey
bool
var
LogFile
string
var
LogFile
string
var
DataDir
string
var
NonInteractive
bool
var
NonInteractive
bool
var
StartJsConsole
bool
var
StartJsConsole
bool
var
InputFile
string
var
InputFile
string
...
@@ -31,22 +30,21 @@ func Init() {
...
@@ -31,22 +30,21 @@ func Init() {
flag
.
PrintDefaults
()
flag
.
PrintDefaults
()
}
}
flag
.
StringVar
(
&
Identifier
,
"i
"
,
""
,
"c
ustom client identifier"
)
flag
.
StringVar
(
&
Identifier
,
"i
d"
,
""
,
"C
ustom client identifier"
)
flag
.
BoolVar
(
&
StartMining
,
"m"
,
false
,
"start dagger mining
"
)
flag
.
StringVar
(
&
OutboundPort
,
"port"
,
"30303"
,
"listening port
"
)
flag
.
BoolVar
(
&
ShowGenesis
,
"g"
,
false
,
"prints genesis header and exits
"
)
flag
.
BoolVar
(
&
UseUPnP
,
"upnp"
,
false
,
"enable UPnP support
"
)
flag
.
BoolVar
(
&
StartRpc
,
"r"
,
false
,
"start rpc server
"
)
flag
.
IntVar
(
&
MaxPeer
,
"maxpeer"
,
10
,
"maximum desired peers
"
)
flag
.
IntVar
(
&
RpcPort
,
"rpcport"
,
8080
,
"port to start json-rpc server on"
)
flag
.
IntVar
(
&
RpcPort
,
"rpcport"
,
8080
,
"port to start json-rpc server on"
)
flag
.
BoolVar
(
&
StartRpc
,
"rpc"
,
false
,
"start rpc server"
)
flag
.
BoolVar
(
&
StartJsConsole
,
"js"
,
false
,
"exp"
)
flag
.
BoolVar
(
&
StartMining
,
"mine"
,
false
,
"start dagger mining"
)
flag
.
BoolVar
(
&
NonInteractive
,
"y"
,
false
,
"non-interactive mode (say yes to confirmations)"
)
flag
.
BoolVar
(
&
NonInteractive
,
"y"
,
false
,
"non-interactive mode (say yes to confirmations)"
)
flag
.
BoolVar
(
&
UseUPnP
,
"upnp"
,
false
,
"enable UPnP support"
)
flag
.
BoolVar
(
&
UseSeed
,
"seed"
,
true
,
"seed peers"
)
flag
.
BoolVar
(
&
UseSeed
,
"seed"
,
true
,
"seed peers"
)
flag
.
BoolVar
(
&
GenAddr
,
"genaddr"
,
false
,
"create a new priv/pub key"
)
flag
.
BoolVar
(
&
GenAddr
,
"genaddr"
,
false
,
"create a new priv/pub key"
)
flag
.
BoolVar
(
&
ExportKey
,
"export"
,
false
,
"export private key"
)
flag
.
BoolVar
(
&
ExportKey
,
"export"
,
false
,
"export private key"
)
flag
.
StringVar
(
&
OutboundPort
,
"p"
,
"30303"
,
"listening port"
)
flag
.
StringVar
(
&
LogFile
,
"logfile"
,
""
,
"log file (defaults to standard output)"
)
flag
.
StringVar
(
&
LogFile
,
"logfile"
,
""
,
"log file (defaults to standard output)"
)
flag
.
StringVar
(
&
DataDir
,
"dir"
,
".ethereum"
,
"ethereum data directory"
)
flag
.
StringVar
(
&
ImportKey
,
"import"
,
""
,
"imports the given private key (hex)"
)
flag
.
StringVar
(
&
ImportKey
,
"import"
,
""
,
"imports the given private key (hex)"
)
flag
.
IntVar
(
&
MaxPeer
,
"x"
,
10
,
"maximum desired peers"
)
flag
.
BoolVar
(
&
StartJsConsole
,
"js"
,
false
,
"exp"
)
flag
.
Parse
()
flag
.
Parse
()
...
...
ethereum/ethereum.go
View file @
5f28013f
...
@@ -59,7 +59,7 @@ func main() {
...
@@ -59,7 +59,7 @@ func main() {
lt
=
ethutil
.
LogFile
|
ethutil
.
LogStd
lt
=
ethutil
.
LogFile
|
ethutil
.
LogStd
}
}
ethutil
.
ReadConfig
(
DataDir
,
lt
,
Identifier
)
ethutil
.
ReadConfig
(
".ethereum"
,
lt
,
Identifier
)
logger
:=
ethutil
.
Config
.
Log
logger
:=
ethutil
.
Config
.
Log
...
...
utils/cmd.go
View file @
5f28013f
...
@@ -33,8 +33,6 @@ func DoMining(ethereum *eth.Ethereum) {
...
@@ -33,8 +33,6 @@ func DoMining(ethereum *eth.Ethereum) {
addr
:=
keyPair
.
Address
()
addr
:=
keyPair
.
Address
()
go
func
()
{
go
func
()
{
ethutil
.
Config
.
Log
.
Infoln
(
"Miner started"
)
miner
=
ethminer
.
NewDefaultMiner
(
addr
,
ethereum
)
miner
=
ethminer
.
NewDefaultMiner
(
addr
,
ethereum
)
// Give it some time to connect with peers
// Give it some time to connect with peers
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment