Browse Source

ncurses forms, Addresses window with NameReg, fix contracts showing twice, mining indicator and other small fixes

cl-refactor
Vincent Gariepy 11 years ago
parent
commit
d3d4d0a2f8
  1. 3
      eth/CMakeLists.txt
  2. 493
      eth/main.cpp

3
eth/CMakeLists.txt

@ -17,17 +17,20 @@ if (${TARGET_PLATFORM} STREQUAL "w64")
target_link_libraries(eth iphlpapi)
target_link_libraries(eth cryptopp)
target_link_libraries(eth ncurses)
target_link_libraries(eth form)
target_link_libraries(eth boost_system-mt-s)
target_link_libraries(eth boost_filesystem-mt-s)
target_link_libraries(eth boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
target_link_libraries(eth ncurses)
target_link_libraries(eth form)
else ()
target_link_libraries(eth ${CRYPTOPP_LIBRARIES})
target_link_libraries(eth boost_system)
target_link_libraries(eth boost_filesystem)
target_link_libraries(eth ncurses)
target_link_libraries(eth form)
find_package(Threads REQUIRED)
target_link_libraries(eth ${CMAKE_THREAD_LIBS_INIT})
endif ()

493
eth/main.cpp

@ -22,6 +22,8 @@
#include <ncurses.h>
#undef OK
#include <form.h>
#undef OK
#include <thread>
#include <chrono>
#include <fstream>
@ -88,8 +90,9 @@ void interactiveHelp()
<< " block Gives the current block height." << endl
<< " balance Gives the current balance." << endl
<< " peers List the peers that are connected" << endl
<< " transact <secret> <dest> <amount> <gasPrice> <gas> <data> Executes a given transaction." << endl
<< " send <dest> <amount> <gasPrice> <gas> Executes a given transaction with current secret." << endl
<< " transact Execute a given transaction." << endl
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " exit Exits the application." << endl;
}
@ -127,6 +130,25 @@ void version()
exit(0);
}
u256 c_minGasPrice = 10000000000000;
u256 c_minGas = 100;
Address c_config = Address("ccdeac59d35627b7de09332e819d5159e7bb7250");
string pretty(h160 _a, eth::State _st)
{
string ns;
h256 n;
if (h160 nameReg = (u160)_st.contractStorage(c_config, 0))
n = _st.contractStorage(nameReg, (u160)(_a));
if (n)
{
std::string s((char const*)n.data(), 32);
if (s.find_first_of('\0') != string::npos)
s.resize(s.find_first_of('\0'));
ns = " " + s;
}
return ns;
}
namespace nc
{
@ -254,6 +276,8 @@ int nc_window_streambuf::sync()
}
vector<string> form_dialog(vector<string> _sfields, vector<string> _lfields, vector<string> _bfields, int _cols, int _rows, string _post_form);
int main(int argc, char** argv)
{
@ -382,7 +406,7 @@ int main(int argc, char** argv)
int y = 0;
int x = 2;
string cmd;
WINDOW * mainwin, * consolewin, * logwin, * blockswin, * pendingwin, * contractswin, * peerswin;
WINDOW * mainwin, * consolewin, * logwin, * blockswin, * pendingwin, *addswin, * contractswin, * peerswin;
if (!(mainwin = initscr()))
{
@ -391,34 +415,43 @@ int main(int argc, char** argv)
}
getmaxyx(mainwin, height, width);
int qheight = height * 3 / 5;
int qwidth = width / 4 - 4;
nonl();
nocbreak();
cbreak();
timeout(30000);
echo();
keypad(mainwin, true);
logwin = newwin(height * 2 / 5 - 2, width, height * 3 / 5, 0);
/* Initialize color pairs */
start_color();
init_pair(1, COLOR_WHITE, COLOR_BLACK);
init_pair(2, COLOR_RED, COLOR_BLACK);
init_pair(3, 7, COLOR_BLACK);
use_default_colors();
logwin = newwin(height * 2 / 5 - 2, width * 2 / 3, qheight, 0);
nc::nc_window_streambuf outbuf(logwin, std::cout);
// nc::nc_window_streambuf errbuf( logwin, std::cerr );
g_logVerbosity = 1; // Force verbosity level for now
consolewin = newwin(height * 3 / 5, width / 4, 0, 0);
consolewin = newwin(qheight, width / 4, 0, 0);
nc::nc_window_streambuf coutbuf(consolewin, ccout);
blockswin = newwin(height * 3 / 5, width / 4, 0, width / 4);
blockswin = newwin(qheight, width / 4, 0, width / 4);
pendingwin = newwin(height * 1 / 5, width / 4, 0, width * 2 / 4);
peerswin = newwin(height * 2 / 5, width / 4, height * 1 / 5, width * 2 / 4);
contractswin = newwin(height * 3 / 5, width / 4, 0, width * 3 / 4);
addswin = newwin(height * 2 / 5 - 2, width / 3, qheight, width * 2 / 3);
contractswin = newwin(qheight, width / 4, 0, width * 3 / 4);
int vl = height * 3 / 5 - 4;
int vl = qheight - 4;
wsetscrreg(consolewin, 1, vl);
wsetscrreg(blockswin, 1, vl);
wsetscrreg(pendingwin, 1, vl);
wsetscrreg(peerswin, 1, vl);
wsetscrreg(addswin, 1, vl);
wsetscrreg(contractswin, 1, vl);
mvwprintw(mainwin, 1, x, "> ");
mvwprintw(mainwin, 1, 1, " > ");
wresize(mainwin, 3, width);
mvwin(mainwin, height - 3, 0);
@ -432,6 +465,7 @@ int main(int argc, char** argv)
wclrtobot(consolewin);
wclrtobot(pendingwin);
wclrtobot(peerswin);
wclrtobot(addswin);
wclrtobot(contractswin);
ccout << credits(true);
@ -449,7 +483,7 @@ int main(int argc, char** argv)
chr = toHex(us.address().asArray()).c_str();
ccout << chr << endl << endl;
mvwprintw(mainwin, 1, x, "> ");
mvwprintw(mainwin, 1, 1, " > ");
clrtoeol();
if (s.length() > 1)
@ -512,28 +546,143 @@ int main(int argc, char** argv)
}
else if (cmd == "transact")
{
string sechex;
string rechex;
u256 amount;
u256 gasPrice;
u256 gas;
iss >> sechex >> rechex >> amount >> gasPrice >> gas;
Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(rechex));
bytes data;
c.transact(secret, amount, dest, data, gas, gasPrice);
vector<string> s;
s.push_back("Address");
vector<string> l;
l.push_back("Amount");
l.push_back("Gas price");
l.push_back("Gas");
vector<string> b;
b.push_back("Secret");
b.push_back("Data");
c.lock();
vector<string> fields = form_dialog(s, l, b, height, width, cmd);
c.unlock();
int fs = fields.size();
if (fs < 6)
{
if (fs > 0)
cwarn << "Missing parameter";
}
else {
fields[0].erase(std::remove(fields[0].begin(), fields[0].end(), ' '), fields[0].end());
fields[4].erase(std::remove(fields[4].begin(), fields[4].end(), ' '), fields[4].end());
fields[5].erase(std::find_if(fields[5].rbegin(), fields[5].rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), fields[5].end());
int size = fields[0].length();
u256 amount = atoll(fields[1].c_str());
u256 gasPrice = atoll(fields[2].c_str());
u256 gas = atoll(fields[3].c_str());
string sechex = fields[4];
string sdata = fields[5];
int ssize = fields[4].length();
if (size < 40) {
if (size > 0)
cwarn << "Invalid address length: " << size;
}
else if (amount < 0)
cwarn << "Invalid amount: " << amount;
else if (gasPrice < c_minGasPrice)
cwarn << "Minimum gas price is " << c_minGasPrice;
else if (gas < c_minGas)
cwarn << "Minimum gas amount is " << c_minGas;
else if (ssize < 40)
{
if (ssize > 0)
cwarn << "Invalid secret length:" << ssize;
}
else {
Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(fields[0]));
bytes data = asBytes(sdata);
c.transact(secret, amount, dest, data, gas, gasPrice);
}
}
}
else if (cmd == "send")
{
string rechex;
u256 amount;
u256 gasPrice;
u256 gas;
iss >> rechex >> amount >> gasPrice >> gas;
Address dest = h160(fromHex(rechex));
c.transact(us.secret(), amount, dest, bytes(), gas, gasPrice);
vector<string> s;
s.push_back("Address");
vector<string> l;
l.push_back("Amount");
vector<string> b;
c.lock();
vector<string> fields = form_dialog(s, l, b, height, width, cmd);
c.unlock();
int fs = fields.size();
if (fs < 2)
{
if (fs > 0)
cwarn << "Missing parameter";
}
else {
fields[0].erase(std::remove(fields[0].begin(), fields[0].end(), ' '), fields[0].end());
int size = fields[0].length();
u256 amount = atoll(fields[1].c_str());
if (size < 40) {
if (size > 0)
cwarn << "Invalid address length: " << size;
}
else if (amount <= 0)
cwarn << "Invalid amount: " << amount;
else
{
u256 gasPrice = c_minGasPrice;
u256 gas = c_minGas;
Address dest = h160(fromHex(fields[0]));
c.transact(us.secret(), amount, dest, bytes(), gas, gasPrice);
}
}
}
else if (cmd == "contract")
{
vector<string> s;
vector<string> l;
l.push_back("Endowment");
l.push_back("Gas price");
l.push_back("Gas");
vector<string> b;
b.push_back("Code");
b.push_back("Init");
c.lock();
vector<string> fields = form_dialog(s, l, b, height, width, cmd);
c.unlock();
int fs = fields.size();
if (fs < 5) {
if (fs > 0)
cwarn << "Missing parameter";
}
else {
u256 endowment = atoll(fields[0].c_str());
u256 gas = atoll(fields[2].c_str());
u256 gasPrice = atoll(fields[1].c_str());
if (endowment < 0)
cwarn << "Invalid endowment";
else if (gasPrice < c_minGasPrice)
cwarn << "Minimum gas price is " << c_minGasPrice;
else if (gas < c_minGas)
cwarn << "Minimum gas amount is " << c_minGas;
else
{
fields[3].erase(std::find_if(fields[3].rbegin(), fields[3].rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), fields[3].end());
fields[4].erase(std::find_if(fields[4].rbegin(), fields[4].rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), fields[4].end());
string scode = fields[3];
string sinit = fields[4];
int size = scode.length();
cout << "Code:" << endl << scode << endl;
cout << "Init:" << endl << sinit << endl;
cout << "Code size: " << size << endl;
if (size < 1)
cwarn << "No code submitted";
else
{
eth::bytes code = assemble(scode);
cout << "Assembled:" << endl << code << endl;
eth::bytes init = assemble(sinit);
cout << "Init:" << endl << init << endl;
c.transact(us.secret(), endowment, code, init, gas, gasPrice);
}
}
}
}
else if (cmd == "inspect")
{
@ -541,7 +690,7 @@ int main(int argc, char** argv)
iss >> rechex;
if (rechex.length() != 40)
cout << "Invalid address length" << endl;
cwarn << "Invalid address length";
else
{
c.lock();
@ -605,13 +754,12 @@ int main(int argc, char** argv)
// Blocks
auto const& st = c.state();
auto const& bc = c.blockChain();
y = 0;
y = 1;
for (auto h = bc.currentHash(); h != bc.genesisHash(); h = bc.details(h).parent)
{
auto d = bc.details(h);
string s = "# " + std::to_string(d.number) + ' ' + toString(h); // .abridged();
y += 1;
mvwaddnstr(blockswin, y, x, s.c_str(), qwidth);
mvwaddnstr(blockswin, y++, x, s.c_str(), qwidth);
for (auto const& i: RLP(bc.block(h))[1])
{
@ -620,53 +768,57 @@ int main(int argc, char** argv)
ss = t.receiveAddress ?
" " + toString(toHex(t.safeSender().asArray())) + " " + (st.isContractAddress(t.receiveAddress) ? '*' : '-') + "> " + toString(t.receiveAddress) + ": " + toString(formatBalance(t.value)) + " [" + toString((unsigned)t.nonce) + "]":
" " + toString(toHex(t.safeSender().asArray())) + " +> " + toString(right160(t.sha3())) + ": " + toString(formatBalance(t.value)) + " [" + toString((unsigned)t.nonce) + "]";
y += 1;
mvwaddnstr(blockswin, y, x, ss.c_str(), qwidth - 2);
if (y > height * 3 / 5 - 2)
mvwaddnstr(blockswin, y++, x, ss.c_str(), qwidth - 2);
if (y > qheight - 2)
break;
}
if (y > height * 3 / 5 - 2)
if (y > qheight - 2)
break;
}
// Pending
y = 0;
for (Transaction const& t: c.pending())
y = 1;
auto aps = c.pending();
for (auto const& t: aps)
{
string ss;
if (t.receiveAddress)
ss = toString(toHex(t.safeSender().asArray())) + " " + (st.isContractAddress(t.receiveAddress) ? '*' : '-') + "> " + toString(t.receiveAddress) + ": " + toString(formatBalance(t.value)) + " " + " [" + toString((unsigned)t.nonce) + "]";
else
ss = toString(toHex(t.safeSender().asArray())) + " +> " + toString(right160(t.sha3())) + ": " + toString(formatBalance(t.value)) + "[" + toString((unsigned)t.nonce) + "]";
y += 1;
mvwaddnstr(pendingwin, y, x, ss.c_str(), qwidth);
if (y > height * 3 / 5 - 4)
mvwaddnstr(pendingwin, y++, x, ss.c_str(), qwidth);
if (y > qheight - 4)
break;
}
// Contracts
// Contracts and addresses
y = 1;
int cc = 1;
auto acs = st.addresses();
y = 0;
for (auto n = 0; n < 2; ++n)
for (auto const& i: acs)
{
auto r = i.first;
for (auto const& i: acs)
{
auto r = i.first;
if (st.isContractAddress(r))
{
string ss;
ss = toString(r) + " : " + toString(formatBalance(i.second)) + " [" + toString((unsigned)st.transactionsFrom(i.first)) + "]";
y += 1;
mvwaddnstr(contractswin, y, x, ss.c_str(), qwidth);
if (y > height * 3 / 5 - 2)
break;
}
string ss;
ss = toString(r) + pretty(r, st) + " : " + toString(formatBalance(i.second)) + " [" + toString((unsigned)st.transactionsFrom(i.first)) + "]";
mvwaddnstr(addswin, y++, x, ss.c_str(), width / 2 - 4);
scrollok(addswin, true);
if (st.isContractAddress(r))
{
ss = toString(r) + " : " + toString(formatBalance(i.second)) + " [" + toString((unsigned)st.transactionsFrom(i.first)) + "]";
mvwaddnstr(contractswin, cc++, x, ss.c_str(), qwidth);
if (cc > qheight - 2)
break;
}
if (y > height * 2 / 5 - 2)
break;
}
// Peers
y = 0;
y = 1;
string psc;
string pss;
auto cp = c.peers();
@ -674,8 +826,7 @@ int main(int argc, char** argv)
for (PeerInfo const& i: cp)
{
pss = toString(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()) + " ms - " + i.host + ":" + toString(i.port) + " - " + i.clientVersion;
y += 1;
mvwaddnstr(peerswin, y, x, pss.c_str(), qwidth);
mvwaddnstr(peerswin, y++, x, pss.c_str(), qwidth);
if (y > height * 2 / 5 - 4)
break;
}
@ -684,15 +835,18 @@ int main(int argc, char** argv)
box(blockswin, 0, 0);
box(pendingwin, 0, 0);
box(peerswin, 0, 0);
box(addswin, 0, 0);
box(contractswin, 0, 0);
box(mainwin, 0, 0);
// Balance
mvwprintw(consolewin, 0, x, "Balance: ");
stringstream ssb;
u256 balance = c.state().balance(us.address());
chr = toString(balance).c_str();
mvwprintw(consolewin, 0, 11, chr);
wmove(consolewin, 1, x);
Address gavCoin("91a10664d0cd489085a7a018beb5245d4f2272f1");
u256 totalGavCoinBalance = st.contractStorage(gavCoin, (u160)us.address());
ssb << "Balance: " << formatBalance(balance) << " | " << totalGavCoinBalance << " GAV";
mvwprintw(consolewin, 0, x, ssb.str().c_str());
mvwprintw(consolewin, 0, x, ssb.str().c_str());
// Block
mvwprintw(blockswin, 0, x, "Block # ");
@ -700,22 +854,45 @@ int main(int argc, char** argv)
chr = toString(n).c_str();
mvwprintw(blockswin, 0, 10, chr);
mvwprintw(pendingwin, 0, x, "Pending");
mvwprintw(contractswin, 0, x, "Contracts");
// Pending
string pc;
pc = "Pending: " + toString(c.pending().size());
mvwprintw(pendingwin, 0, x, pc.c_str());
// Contracts
string sc = "Contracts: ";
sc += toString(cc - 1);
mvwprintw(contractswin, 0, x, sc.c_str());
// Peers
mvwprintw(peerswin, 0, x, "Peers: ");
chr = toString(c.peers().size()).c_str();
mvwprintw(peerswin, 0, 9, chr);
// Mining flag
if (c.isMining())
mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON");
else
mvwprintw(consolewin, qheight - 1, width / 4 - 12, "Mining OFF");
wmove(consolewin, 1, x);
// Addresses
string ac;
ac = "Addresses: " + toString(acs.size());
mvwprintw(addswin, 0, x, ac.c_str());
wrefresh(consolewin);
wrefresh(blockswin);
wrefresh(pendingwin);
wrefresh(peerswin);
wrefresh(addswin);
wrefresh(contractswin);
wrefresh(mainwin);
}
delwin(addswin);
delwin(contractswin);
delwin(peerswin);
delwin(pendingwin);
@ -744,3 +921,183 @@ int main(int argc, char** argv)
return 0;
}
void print_in_middle(WINDOW *win, int starty, int startx, int width, string str, chtype color)
{
int length;
int x = 0;
int y = 0;
float temp;
if (startx != 0)
x = startx;
if (starty != 0)
y = starty;
if (width == 0)
width = 80;
length = str.length();
temp = (width - length) / 2;
x = startx + (int)temp;
wattron(win, color);
mvwprintw(win, y, x, "%s", str.c_str());
wattroff(win, color);
refresh();
}
vector<string> form_dialog(vector<string> _sv, vector<string> _lv, vector<string> _bv, int _cols, int _rows, string _post_form)
{
vector<string> vs;
WINDOW *form_win;
int _sfields = _sv.size();
int _lfields = _lv.size();
int _bfields = _bv.size();
int maxfields = _sfields + _lfields + _bfields;
FIELD *field[maxfields];
int ch;
int starty = 6;
int height = _cols;
int width = _rows;
/* Initialize the fields */
int si;
int li;
int bi = 0;
vector<int> labels;
for (si = 0; si < _sfields; ++si)
{
starty++; // Leave room for our labels, no window yet so that or fake fields...
field[si] = new_field(1, 40, starty++, 1, 0, 0);
labels.push_back(starty);
set_field_back(field[si], A_UNDERLINE);
set_field_type(field[si], TYPE_ALNUM, 40);
}
for (li = _sfields; li < _sfields + _lfields; ++li)
{
starty++;
field[li] = new_field(1, 64, starty++, 1, 3, 0);
labels.push_back(starty);
set_field_back(field[li], A_UNDERLINE);
}
for (bi = _sfields + _lfields; bi < maxfields; ++bi)
{
starty++;
field[bi] = new_field(5, 72, starty++, 1, 0, 0);
labels.push_back(starty);
field_opts_off(field[bi], O_STATIC);
set_field_back(field[bi], A_UNDERLINE);
starty += 4;
}
field[maxfields] = NULL;
/* Create the form and post it */
FORM *form = new_form(field);
/* Calculate the area required for the form */
scale_form(form, &_rows, &_cols);
/* Create the window to be associated with the form */
form_win = newwin(_rows + 4, _cols + 8, (height / 2 - _rows / 2 - 2), (width / 2 - _cols / 2 - 2));
/* Set main window and sub window */
set_form_win(form, form_win);
set_form_sub(form, derwin(form_win, _rows, _cols, 2, 2));
nodelay(form_win, true);
keypad(form_win, true);
noecho();
timeout(0);
box(form_win, 0, 0);
print_in_middle(form_win, 1, 0, _cols, _post_form, COLOR_PAIR(2));
post_form(form);
// Set labels
int ca = 0;
int cf;
for (cf = 0; cf < _sfields; ++cf)
{
wattron(form_win, COLOR_PAIR(3));
mvwprintw(form_win, labels[ca], 3, _sv[cf].c_str());
wattroff(form_win, COLOR_PAIR(3));
ca++;
}
for (cf = 0; cf < _lfields; ++cf)
{
wattron(form_win, COLOR_PAIR(3));
mvwprintw(form_win, labels[ca], 3, _lv[cf].c_str());
mvwprintw(form_win, labels[ca] + 1, _cols - 1, "wei");
wattroff(form_win, COLOR_PAIR(3));
ca++;
}
for (cf = 0; cf < _bfields; ++cf)
{
wattron(form_win, COLOR_PAIR(3));
mvwprintw(form_win, labels[ca], 3, _bv[cf].c_str());
wattroff(form_win, COLOR_PAIR(3));
ca++;
}
wrefresh(form_win);
print_in_middle(form_win, 3, 0, _cols, string("Use the TAB key to switch between fields."), COLOR_PAIR(1));
print_in_middle(form_win, 4, 0, _cols, string("Use UP, DOWN arrow keys to switch between lines."), COLOR_PAIR(1));
print_in_middle(form_win, 6, 0, _cols, string("Press ENTER to submit the form and ESC to cancel."), COLOR_PAIR(1));
refresh();
while ((ch = wgetch(form_win)) != 27 and ch != 13) // KEY_F(1))
{
switch (ch)
{
case 9: // Tab
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_DOWN:
form_driver(form, REQ_NEXT_LINE);
break;
case KEY_UP:
form_driver(form, REQ_PREV_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_LEFT_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_RIGHT_CHAR);
break;
case KEY_BACKSPACE: // Backspace
case KEY_DC:
case KEY_DL:
case 127:
form_driver(form, REQ_DEL_PREV);
wrefresh(form_win);
break;
case KEY_ENTER: // Enter
case 13:
case 27: // Esc
break;
default:
form_driver(form, ch);
break;
}
}
if (form_driver(form, REQ_VALIDATION) != E_OK)
cwarn << "Validation error";
int fi;
for (fi = 0; fi < maxfields; ++fi)
free_field(field[fi]);
free_form(form);
unpost_form(form);
echo();
timeout(30000);
delwin(form_win);
if (ch == 13)
for (int fi = 0; fi < maxfields; ++fi)
vs.push_back(field_buffer(field[fi], 0));
return vs;
}

Loading…
Cancel
Save