Browse Source

Merge branch 'develop' into quickgui

Conflicts:
	TODO
cl-refactor
Gav Wood 11 years ago
parent
commit
8bc040d2d4
  1. 55
      BuildInfo.sh
  2. 12
      CMakeLists.txt
  3. 4
      README.md
  4. 94
      TODO
  5. 4
      alethzero/CMakeLists.txt
  6. 40
      alethzero/MainWin.cpp
  7. 2
      alethzero/MainWin.h
  8. 6
      debian/README.Debian
  9. 9
      debian/README.source
  10. 23
      debian/changelog
  11. 1
      debian/compat
  12. 29
      debian/control
  13. 24
      debian/copyright
  14. 3
      debian/docs
  15. 36
      debian/rules
  16. 23
      eth/main.cpp
  17. 2
      libethereum/BlockChain.cpp
  18. 3
      libethereum/BlockChain.h
  19. 41
      libethereum/Client.cpp
  20. 19
      libethereum/Client.h
  21. 280
      libethereum/Common.cpp
  22. 617
      libethereum/Common.h
  23. 96
      libethereum/CommonData.cpp
  24. 186
      libethereum/CommonData.h
  25. 200
      libethereum/CommonEth.cpp
  26. 137
      libethereum/CommonEth.h
  27. 48
      libethereum/CommonIO.cpp
  28. 223
      libethereum/CommonIO.h
  29. 3
      libethereum/Dagger.h
  30. 1
      libethereum/Defaults.h
  31. 12
      libethereum/Exceptions.h
  32. 8
      libethereum/FeeStructure.h
  33. 25
      libethereum/FixedHash.cpp
  34. 195
      libethereum/FixedHash.h
  35. 3
      libethereum/Instruction.cpp
  36. 16
      libethereum/Instruction.h
  37. 41
      libethereum/Log.cpp
  38. 134
      libethereum/Log.h
  39. 1066
      libethereum/PeerNetwork.cpp
  40. 166
      libethereum/PeerNetwork.h
  41. 542
      libethereum/PeerServer.cpp
  42. 133
      libethereum/PeerServer.h
  43. 585
      libethereum/PeerSession.cpp
  44. 90
      libethereum/PeerSession.h
  45. 53
      libethereum/State.cpp
  46. 4
      libethereum/State.h
  47. 24
      libethereum/Transaction.cpp
  48. 2
      libethereum/Transaction.h
  49. 25
      libethereum/TransactionQueue.cpp
  50. 6
      libethereum/TransactionQueue.h
  51. 6
      libethereum/TrieDB.h
  52. 1
      libethereum/UPnP.cpp
  53. 8
      libethereum/VM.h
  54. 8
      package.sh
  55. 65
      release.sh
  56. 15
      test/MemTrie.cpp
  57. 3
      test/MemTrie.h
  58. 15
      test/TrieHash.cpp
  59. 3
      test/TrieHash.h
  60. 37
      test/crypto.cpp
  61. 1
      test/dagger.cpp
  62. 7
      test/hexPrefix.cpp
  63. 2
      test/main.cpp
  64. 2
      test/peer.cpp
  65. 5
      test/rlp.cpp
  66. 12
      test/trie.cpp
  67. 1
      test/vm.cpp
  68. 33
      windows/Alethzero.vcxproj
  69. 3
      windows/Alethzero.vcxproj.filters
  70. 25
      windows/BuildInfo.lua
  71. 25
      windows/Ethereum.vcxproj
  72. 16
      windows/Ethereum.vcxproj.filters
  73. 6
      windows/LibEthereum.props
  74. 6
      windows/UseQt.props

55
BuildInfo.sh

@ -0,0 +1,55 @@
CURRENT_SOURCE_DIR=$1
CURRENT_BINARY_DIR=$2
BUILD_TYPE=$3
BUILD_PLATFORM=$4
echo "Current source dir: $CURRENT_SOURCE_DIR"
echo "Current binary dir: $CURRENT_BINARY_DIR"
echo "Build type: $BUILD_TYPE"
echo "Build platform: $BUILD_PLATFORM"
if [[ -e "$CURRENT_SOURCE_DIR/BuildInfo.h" ]]
then
echo "Using existing BuildInfo.h"
cp $CURRENT_SOURCE_DIR/BuildInfo.h $CURRENT_BINARY_DIR/BuildInfo.h.tmp
else
if [[ -e "$CURRENT_SOURCE_DIR/.git" ]]
then
ETH_COMMIT_HASH=$(git --git-dir=$CURRENT_SOURCE_DIR/.git --work-tree=$CURRENT_SOURCE_DIR rev-parse HEAD)
ETH_LOCAL_CHANGES=$(git --git-dir=$CURRENT_SOURCE_DIR/.git --work-tree=$CURRENT_SOURCE_DIR diff --shortstat)
if [[ -z "$ETH_LOCAL_CHANGES" ]]
then
ETH_CLEAN_REPO=1
else
ETH_CLEAN_REPO=0
fi
echo "Commit hash: ${ETH_COMMIT_HASH} (Clean: ${ETH_CLEAN_REPO} - ${ETH_LOCAL_CHANGES})"
else
echo "Unknown repo."
ETH_COMMIT_HASH=0
ETH_CLEAN_REPO=1
fi
echo "// This file was automatically generated by cmake" > $CURRENT_BINARY_DIR/BuildInfo.h.tmp
echo "" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp
echo "#pragma once" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp
echo "" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp
echo "#define ETH_COMMIT_HASH $ETH_COMMIT_HASH" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp
echo "#define ETH_CLEAN_REPO $ETH_CLEAN_REPO" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp
echo "#define ETH_BUILD_TYPE $BUILD_TYPE" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp
echo "#define ETH_BUILD_PLATFORM $BUILD_PLATFORM" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp
fi
if [[ -e "$CURRENT_BINARY_DIR/BuildInfo.h" ]]
then
DIFF=$(diff $CURRENT_BINARY_DIR/BuildInfo.h $CURRENT_BINARY_DIR/BuildInfo.h.tmp)
if [[ -z "$DIFF" ]]
then
rm $CURRENT_BINARY_DIR/BuildInfo.h.tmp
else
mv $CURRENT_BINARY_DIR/BuildInfo.h.tmp $CURRENT_BINARY_DIR/BuildInfo.h
fi
else
mv $CURRENT_BINARY_DIR/BuildInfo.h.tmp $CURRENT_BINARY_DIR/BuildInfo.h
fi

12
CMakeLists.txt

@ -141,17 +141,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Generate header file containing useful build information # Generate header file containing useful build information
execute_process(COMMAND git --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git --work-tree=${CMAKE_CURRENT_SOURCE_DIR} rev-parse HEAD OUTPUT_VARIABLE ETH_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) add_custom_target(BuildInfo.h ALL COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BUILD_TYPE} ${ETH_BUILD_PLATFORM})
execute_process(COMMAND git --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git --work-tree=${CMAKE_CURRENT_SOURCE_DIR} diff --shortstat OUTPUT_VARIABLE ETH_LOCAL_CHANGES OUTPUT_STRIP_TRAILING_WHITESPACE)
if("x${ETH_LOCAL_CHANGES}" STREQUAL "x")
set(ETH_CLEAN_REPO 1)
else()
set(ETH_CLEAN_REPO 0)
endif()
message("Commit Hash: ${ETH_COMMIT_HASH} (Clean: ${ETH_CLEAN_REPO} - ${ETH_LOCAL_CHANGES})")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/BuildInfo.h "// This file was automatically generated by cmake\n#pragma once\n\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/BuildInfo.h "#define ETH_COMMIT_HASH ${ETH_COMMIT_HASH}\n#define ETH_CLEAN_REPO ${ETH_CLEAN_REPO}\n#define ETH_BUILD_TYPE ${CMAKE_BUILD_TYPE}\n#define ETH_BUILD_PLATFORM ${ETH_BUILD_PLATFORM}\n")
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(secp256k1) add_subdirectory(secp256k1)

4
README.md

@ -8,7 +8,7 @@ Contributors, builders and testers include Eric Lombrozo (cross-compilation), Ti
### Building ### Building
See https://github.com/ethereum/cpp-ethereum/wiki/Building and https://github.com/ethereum/cpp-ethereum/wiki/Compatibility-Info-and-Build-Tips . See https://github.com/ethereum/cpp-ethereum/wiki/Build-Instructions and https://github.com/ethereum/cpp-ethereum/wiki/Compatibility-Info-and-Build-Tips .
### Testing ### Testing
@ -16,7 +16,7 @@ To run the tests, make sure you clone the tests repository from github.com/ether
### Yet To Do ### Yet To Do
See TODO See https://github.com/ethereum/cpp-ethereum/wiki/TODO
### License ### License

94
TODO

@ -1,94 +0,0 @@
### UP FOR GRABS
BUG: Nonce sometimes jumps one.
Tests
- Use standard tests.
Crypto stuff:
- kFromMessage
- Check all the tweak instructions.
Network:
- *** Exponential backoff on bad connection.
- *** Handle exception when no network.
- *** Only download blocks from one peer at once.
- Download in parallel, but stripe.
- NotInChain will be very bad for new peers - it'll run through until the genesis.
- Check how many it has first.
- Crypto on network - use id as public key?
- Make work with IPv6
- Peers rated.
- Useful/useless - new blocks/transactions or useful peers?
- Solid communications?
- Strategy for peer suggestion?
- Ignore transactions with future nonces until address's nonce changes.
Cleanups & caching
- All caches should flush unused data (I'm looking at you, BlockChain) to avoid memory overload.
- State DB should keep only last few N blocks worth of nodes (except for restore points - configurable, defaults to every 30000th block - all blocks that are restore points should be stored so their stateRoots are known good).
THREAD-SAFETY
- BlockChain
- TransactionQueue
- State
General:
- Better logging.
- Colours.
- Move over to new system.
- Remove block chain on protocol change (i.e. store protocol with block chain).
Robustness
- Remove aborts
- Recover from all exceptions.
- Especially RLP & other I/O.
- RLP should never assert; only throw.
- Store version alongside BC DB.
- Better handling of corrupt blocks.
- Kill DB & restart.
- Avoid transactions with future invalid nonces until additional transactions are processed.
GUI
- Make address/block chain list model-based, JIT populated.
- Make everything else model-based
- Qt/QML class.
- Turn on/off debug channels.
### Marko
Ubuntu builds
- Raring (branch, local, x64 only :-( )
- Quantal (branch) (Launchpad)
- Saucy (master) (Launchpad)
### Alex
Mac build.
Mac build instructions.
### Eric
Windows XC build.
Windows XC build instructions.
### Tim/Harv
Windows MSVC build.
Windows MSVC build instructions.
LATER:
Trie on DB.
- Move the restore point stuff into block restore points
- i.e. keep all nodes from last 127 blocks with counter, at 128, kill but keep every (60*24*7)th or so i.e. one per week as a restore point.
- maybe allow this to be configured.
### TIM
Stateful Miner class.
Better Mod-Exp.

4
alethzero/CMakeLists.txt

@ -87,10 +87,12 @@ elseif (${TARGET_PLATFORM} STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-keep-inline-dllexport -static-libgcc -static-libstdc++ -static") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-keep-inline-dllexport -static-libgcc -static-libstdc++ -static")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-s -Wl,-subsystem,windows -mthreads -L/usr/x86_64-w64-mingw32/plugins/platforms") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-s -Wl,-subsystem,windows -mthreads -L/usr/x86_64-w64-mingw32/plugins/platforms")
target_link_libraries(${EXECUTEABLE} gcc) target_link_libraries(${EXECUTEABLE} gcc)
target_link_libraries(${EXECUTEABLE} mingw32 qtmain mswsock iphlpapi qwindows shlwapi Qt5PlatformSupport gdi32 comdlg32 oleaut32 imm32 winmm ole32 uuid ws2_32) target_link_libraries(${EXECUTEABLE} mingw32 qtmain mswsock iphlpapi qwindows shlwapi Qt5PlatformSupport opengl32 gdi32 comdlg32 oleaut32 imm32 winmm ole32 uuid ws2_32)
target_link_libraries(${EXECUTEABLE} boost_system-mt-s) target_link_libraries(${EXECUTEABLE} boost_system-mt-s)
target_link_libraries(${EXECUTEABLE} boost_filesystem-mt-s) target_link_libraries(${EXECUTEABLE} boost_filesystem-mt-s)
target_link_libraries(${EXECUTEABLE} boost_thread_win32-mt-s) target_link_libraries(${EXECUTEABLE} boost_thread_win32-mt-s)
# target_link_libraries(${EXECUTEABLE} ssl)
target_link_libraries(${EXECUTEABLE} crypt32)
target_link_libraries(${EXECUTEABLE} Qt5PlatformSupport) target_link_libraries(${EXECUTEABLE} Qt5PlatformSupport)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
else () else ()

40
alethzero/MainWin.cpp

@ -6,6 +6,7 @@
#include <libethereum/Dagger.h> #include <libethereum/Dagger.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/Instruction.h> #include <libethereum/Instruction.h>
#include <libethereum/PeerServer.h>
#include "BuildInfo.h" #include "BuildInfo.h"
#include "MainWin.h" #include "MainWin.h"
#include "ui_Main.h" #include "ui_Main.h"
@ -30,12 +31,12 @@ using eth::Secret;
using eth::Transaction; using eth::Transaction;
// functions // functions
using eth::asHex; using eth::toHex;
using eth::assemble; using eth::assemble;
using eth::compileLisp; using eth::compileLisp;
using eth::disassemble; using eth::disassemble;
using eth::formatBalance; using eth::formatBalance;
using eth::fromUserHex; using eth::fromHex;
using eth::right160; using eth::right160;
using eth::simpleDebugOut; using eth::simpleDebugOut;
using eth::toLog2; using eth::toLog2;
@ -78,14 +79,20 @@ Main::Main(QWidget *parent) :
#if ETH_DEBUG #if ETH_DEBUG
m_servers.append("192.168.0.10:30301"); m_servers.append("192.168.0.10:30301");
#else #else
connect(&m_webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* _r) int pocnumber = QString(ETH_QUOTED(ETH_VERSION)).section('.', 1, 1).toInt();
if (pocnumber == 3)
m_servers.push_back("54.201.28.117:30303");
else
{ {
m_servers = QString::fromUtf8(_r->readAll()).split("\n", QString::SkipEmptyParts); connect(&m_webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* _r)
}); {
QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc" + QString(ETH_QUOTED(ETH_VERSION)).section('.', 1, 1) + ".txt")); m_servers = QString::fromUtf8(_r->readAll()).split("\n", QString::SkipEmptyParts);
r.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1712.0 Safari/537.36"); });
m_webCtrl.get(r); QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc" + QString::number(pocnumber) + ".txt"));
srand(time(0)); r.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1712.0 Safari/537.36");
m_webCtrl.get(r);
srand(time(0));
}
#endif #endif
on_verbosity_sliderMoved(); on_verbosity_sliderMoved();
@ -135,7 +142,7 @@ Address Main::fromString(QString const& _a) const
if (h256 a = state().contractMemory(m_nameReg, n)) if (h256 a = state().contractMemory(m_nameReg, n))
return right160(a); return right160(a);
if (_a.size() == 40) if (_a.size() == 40)
return Address(fromUserHex(_a.toStdString())); return Address(fromHex(_a.toStdString()));
else else
return Address(); return Address();
} }
@ -202,7 +209,10 @@ void Main::readSettings()
ui->clientName->setText(s.value("clientName", "").toString()); ui->clientName->setText(s.value("clientName", "").toString());
ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt()); ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt());
ui->port->setValue(s.value("port", ui->port->value()).toInt()); ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "11f62328e131dbb05ce4c73a3de3c7ab1c84a163").toString()); if (s.value("nameReg").toString() == "11f62328e131dbb05ce4c73a3de3c7ab1c84a163")
s.remove("nameReg");
ui->nameReg->setText(s.value("nameReg", "8ff91e5b145a23ab1afef34f12587c18bd42aec0").toString());
} }
void Main::on_nameReg_textChanged() void Main::on_nameReg_textChanged()
@ -210,7 +220,7 @@ void Main::on_nameReg_textChanged()
string s = ui->nameReg->text().toStdString(); string s = ui->nameReg->text().toStdString();
if (s.size() == 40) if (s.size() == 40)
{ {
m_nameReg = Address(fromUserHex(s)); m_nameReg = Address(fromHex(s));
refresh(true); refresh(true);
} }
} }
@ -464,7 +474,7 @@ void Main::on_ourAccounts_doubleClicked()
{ {
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(asHex(h.asArray()))); qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
} }
void Main::on_log_doubleClicked() void Main::on_log_doubleClicked()
@ -476,14 +486,14 @@ void Main::on_accounts_doubleClicked()
{ {
auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(asHex(h.asArray()))); qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
} }
void Main::on_contracts_doubleClicked() void Main::on_contracts_doubleClicked()
{ {
auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray(); auto hba = ui->contracts->currentItem()->data(Qt::UserRole).toByteArray();
auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer);
qApp->clipboard()->setText(QString::fromStdString(asHex(h.asArray()))); qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray())));
} }
void Main::on_destination_textChanged() void Main::on_destination_textChanged()

2
alethzero/MainWin.h

@ -5,7 +5,7 @@
#include <QtCore/QAbstractListModel> #include <QtCore/QAbstractListModel>
#include <QtCore/QMutex> #include <QtCore/QMutex>
#include <QtWidgets/QMainWindow> #include <QtWidgets/QMainWindow>
#include <libethereum/Common.h> #include <libethereum/CommonEth.h>
namespace Ui { namespace Ui {
class Main; class Main;

6
debian/README.Debian

@ -1,6 +0,0 @@
cpp-ethereum for Debian
-----------------------
<possible notes regarding this package - if none, delete this file>
-- Gav <Gav Wood <i@gavwood.com>> Mon, 03 Feb 2014 14:50:20 +0000

9
debian/README.source

@ -1,9 +0,0 @@
cpp-ethereum for Debian
-----------------------
<this file describes information about the source package, see Debian policy
manual section 4.14. You WILL either need to modify or delete this file>

23
debian/changelog

@ -1,23 +0,0 @@
cpp-ethereum (0.1.0-1) saucy; urgency=low
* Various improvements moving towards PoC-2.
-- Ethereum (Ethereum Project) <ethereum@gavwood.com> Fri, 07 Feb 2014 00:48:26 +0000
cpp-ethereum (0.1-3) saucy; urgency=low
* Packaging stuff.
-- Ethereum (Ethereum Project) <ethereum@gavwood.com> Thu, 06 Feb 2014 14:13:00 +0000
cpp-ethereum (0.1-2) saucy; urgency=low
* Fix Qt dep.
-- Gav Wood <ethereum@gavwood.com> Mon, 06 Feb 2014 11:35:20 +0000
cpp-ethereum (0.1-1) saucy; urgency=low
* Initial release.
-- Gav Wood <ethereum@gavwood.com> Mon, 03 Feb 2014 14:50:20 +0000

1
debian/compat

@ -1 +0,0 @@
8

29
debian/control

@ -1,29 +0,0 @@
Source: cpp-ethereum
Section: science
Priority: extra
Maintainer: Ethereum (Ethereum Project) <ethereum@gavwood.com>
Build-Depends: debhelper (>= 8.0.0), cmake, libgmp-dev, libcryptoppeth-dev, libboost-filesystem1.53-dev, libboost-mpi1.53-dev, libboost1.53-dev, libleveldb-dev, libminiupnpc-dev, qtbase5-dev, qt5-default
Standards-Version: 3.9.4
Homepage: http://ethereum.org
#Vcs-Git: git://git.debian.org/collab-maint/cpp-ethereum.git
#Vcs-Browser: http://git.debian.org/?p=collab-maint/cpp-ethereum.git;a=summary
Package: libethereum
Section: libdevel
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libgmp, libcryptoppeth, libboost-filesystem1.53.0, libboost-mpi1.53.0, libleveldb, libminiupnpc, secp256k1eth
Description: The future of computational social contracts.
A long description of libethereum.
Package: libethereum-dev
Section: libdevel
Architecture: any
Depends: libethereum (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, libgmp, libcryptoppeth, libboost-filesystem1.53.0, libboost-mpi1.53.0, libleveldb, libminiupnpc
Description: The future of computational social contracts. Dev Files.
A long description of libethereum. Dev Files.
Package: alethzero
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libethereum (= ${binary:Version}), qtbase5
Description: The Qt-based Ethereum GUI.
A long description of alethzero.

24
debian/copyright

@ -1,24 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: cpp-ethereum
Source: github.com/ethereum/cpp-ethereum
Files: *
Copyright: 2014 Gav Wood <i@gavwood.com>
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

3
debian/docs

@ -1,3 +0,0 @@
CodingStandards.txt
README.md
TODO

36
debian/rules

@ -1,36 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
#
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
#
# Modified to make a template file for a multi-binary package with separated
# build-arch and build-indep targets by Bill Allombert 2001
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# This has to be exported to make some magic below work.
export DH_OPTIONS
%:
dh $@
override_dh_auto_configure:
cmake -DCMAKE_INSTALL_PREFIX=$(CURDIR)/debian/libethereum-dev/usr .
override_dh_auto_build:
$(MAKE) -j8
override_dh_auto_install:
$(MAKE) install
# Move the libs over to the non-dev package.
mkdir -p $(CURDIR)/debian/libethereum/usr
mv $(CURDIR)/debian/libethereum-dev/usr/lib $(CURDIR)/debian/libethereum/usr/lib
mkdir -p $(CURDIR)/debian/alephzero/usr/bin
mv $(CURDIR)/debian/libethereum-dev/usr/bin/alethzero $(CURDIR)/debian/alethzero/usr/lib

23
eth/main.cpp

@ -138,9 +138,9 @@ int main(int argc, char** argv)
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i]; clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
coinbase = h160(fromUserHex(argv[++i])); coinbase = h160(fromHex(argv[++i]));
else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) else if ((arg == "-s" || arg == "--secret") && i + 1 < argc)
us = KeyPair(h256(fromUserHex(argv[++i]))); us = KeyPair(h256(fromHex(argv[++i])));
else if (arg == "-i" || arg == "--interactive") else if (arg == "-i" || arg == "--interactive")
interactive = true; interactive = true;
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
@ -228,13 +228,20 @@ int main(int argc, char** argv)
else if (cmd == "address") else if (cmd == "address")
{ {
cout << endl; cout << endl;
cout << "Current address: " + asHex(us.address().asArray()) << endl; cout << "Current address: " + toHex(us.address().asArray()) << endl;
cout << "===" << endl; cout << "===" << endl;
} }
else if (cmd == "secret") else if (cmd == "secret")
{ {
cout << endl; cout << endl;
cout << "Current secret: " + asHex(us.secret().asArray()) << endl; cout << "Current secret: " + toHex(us.secret().asArray()) << endl;
cout << "===" << endl;
}
else if (cmd == "block")
{
eth::uint n = c.blockChain().details().number;
cout << endl;
cout << "Current block # " << n << endl;
cout << "===" << endl; cout << "===" << endl;
} }
else if (cmd == "balance") else if (cmd == "balance")
@ -251,8 +258,8 @@ int main(int argc, char** argv)
string rechex; string rechex;
u256 amount; u256 amount;
cin >> sechex >> rechex >> amount; cin >> sechex >> rechex >> amount;
Secret secret = h256(fromUserHex(sechex)); Secret secret = h256(fromHex(sechex));
Address dest = h160(fromUserHex(rechex)); Address dest = h160(fromHex(rechex));
c.transact(secret, dest, amount); c.transact(secret, dest, amount);
} }
else if (cmd == "send") else if (cmd == "send")
@ -260,7 +267,7 @@ int main(int argc, char** argv)
string rechex; string rechex;
u256 amount; u256 amount;
cin >> rechex >> amount; cin >> rechex >> amount;
Address dest = h160(fromUserHex(rechex)); Address dest = h160(fromHex(rechex));
c.transact(us.secret(), dest, amount); c.transact(us.secret(), dest, amount);
} }
else if (cmd == "exit") else if (cmd == "exit")
@ -271,7 +278,7 @@ int main(int argc, char** argv)
} }
else else
{ {
cout << "Address: " << endl << asHex(us.address().asArray()) << endl; cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp); c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
eth::uint n = c.blockChain().details().number; eth::uint n = c.blockChain().details().number;
if (mining) if (mining)

2
libethereum/BlockChain.cpp

@ -45,7 +45,7 @@ std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc)
if (it->key().ToString() != "best") if (it->key().ToString() != "best")
{ {
BlockDetails d(RLP(it->value().ToString())); BlockDetails d(RLP(it->value().ToString()));
_out << asHex(it->key().ToString()) << ": " << d.number << " @ " << d.parent << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parent << (cmp == it->key().ToString() ? " BEST" : "") << std::endl;
} }
delete it; delete it;
return _out; return _out;

3
libethereum/BlockChain.h

@ -22,7 +22,8 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include "Common.h" #include "CommonEth.h"
#include "Log.h"
#include "AddressState.h" #include "AddressState.h"
namespace ldb = leveldb; namespace ldb = leveldb;

41
libethereum/Client.cpp

@ -23,20 +23,45 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <boost/filesystem.hpp>
#include "Common.h" #include "Common.h"
#include "Defaults.h" #include "Defaults.h"
#include "PeerServer.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
VersionChecker::VersionChecker(string const& _dbPath, unsigned _protocolVersion):
m_path(_dbPath.size() ? _dbPath : Defaults::dbPath()),
m_protocolVersion(_protocolVersion)
{
m_ok = RLP(contents(m_path + "/protocol")).toInt<unsigned>(RLP::LaisezFaire) == _protocolVersion;
}
void VersionChecker::setOk()
{
if (!m_ok)
{
try
{
boost::filesystem::create_directory(m_path);
}
catch (...) {}
writeFile(m_path + "/protocol", rlp(m_protocolVersion));
}
}
Client::Client(std::string const& _clientVersion, Address _us, std::string const& _dbPath): Client::Client(std::string const& _clientVersion, Address _us, std::string const& _dbPath):
m_clientVersion(_clientVersion), m_clientVersion(_clientVersion),
m_bc(_dbPath), m_vc(_dbPath, PeerServer::protocolVersion()),
m_stateDB(State::openDB(_dbPath)), m_bc(_dbPath, !m_vc.ok()),
m_stateDB(State::openDB(_dbPath, !m_vc.ok())),
m_preMine(_us, m_stateDB), m_preMine(_us, m_stateDB),
m_postMine(_us, m_stateDB), m_postMine(_us, m_stateDB),
m_workState(Active) m_workState(Active)
{ {
Defaults::setDBPath(_dbPath); if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
// Synchronise the state according to the head of the block chain. // Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones. // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
@ -73,6 +98,16 @@ void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHo
connect(_seedHost, _port); connect(_seedHost, _port);
} }
std::vector<PeerInfo> Client::peers()
{
return m_net ? m_net->peers() : std::vector<PeerInfo>();
}
size_t Client::peerCount() const
{
return m_net ? m_net->peerCount() : 0;
}
void Client::connect(std::string const& _seedHost, unsigned short _port) void Client::connect(std::string const& _seedHost, unsigned short _port)
{ {
if (!m_net.get()) if (!m_net.get())

19
libethereum/Client.h

@ -60,6 +60,20 @@ enum ClientWorkState
Deleted Deleted
}; };
class VersionChecker
{
public:
VersionChecker(std::string const& _dbPath, unsigned _protocolVersion);
void setOk();
bool ok() const { return m_ok; }
private:
bool m_ok;
std::string m_path;
unsigned m_protocolVersion;
};
class Client class Client
{ {
public: public:
@ -111,9 +125,9 @@ public:
// Network stuff: // Network stuff:
/// Get information on the current peer set. /// Get information on the current peer set.
std::vector<PeerInfo> peers() { return m_net ? m_net->peers() : std::vector<PeerInfo>(); } std::vector<PeerInfo> peers();
/// Same as peers().size(), but more efficient. /// Same as peers().size(), but more efficient.
size_t peerCount() const { return m_net ? m_net->peerCount() : 0; } size_t peerCount() const;
/// Start the network subsystem. /// Start the network subsystem.
void startNetwork(unsigned short _listenPort = 30303, std::string const& _remoteHost = std::string(), unsigned short _remotePort = 30303, NodeMode _mode = NodeMode::Full, unsigned _peers = 5, std::string const& _publicIP = std::string(), bool _upnp = true); void startNetwork(unsigned short _listenPort = 30303, std::string const& _remoteHost = std::string(), unsigned short _remotePort = 30303, NodeMode _mode = NodeMode::Full, unsigned _peers = 5, std::string const& _publicIP = std::string(), bool _upnp = true);
@ -145,6 +159,7 @@ private:
void work(); void work();
std::string m_clientVersion; ///< Our end-application client's name/version. std::string m_clientVersion; ///< Our end-application client's name/version.
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
BlockChain m_bc; ///< Maintains block database. BlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains list of incoming transactions not yet on the block chain. TransactionQueue m_tq; ///< Maintains list of incoming transactions not yet on the block chain.
Overlay m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it. Overlay m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.

280
libethereum/Common.cpp

@ -21,285 +21,5 @@
#include "Common.h" #include "Common.h"
#include <fstream>
#include <random>
#if WIN32
#pragma warning(push)
#pragma warning(disable:4244)
#else
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#include <secp256k1.h>
#include <sha3.h>
#if WIN32
#pragma warning(pop)
#else
#endif
#include "Exceptions.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
//#define ETH_ADDRESS_DEBUG 1
// Logging
int eth::g_logVerbosity = 8;
map<type_info const*, bool> eth::g_logOverride;
ThreadLocalLogName eth::t_logThreadName("main");
void eth::simpleDebugOut(std::string const& _s, char const*)
{
cout << _s << endl << flush;
}
std::function<void(std::string const&, char const*)> eth::g_logPost = simpleDebugOut;
std::string eth::escaped(std::string const& _s, bool _all)
{
std::string ret;
ret.reserve(_s.size());
ret.push_back('"');
for (auto i: _s)
if (i == '"' && !_all)
ret += "\\\"";
else if (i == '\\' && !_all)
ret += "\\\\";
else if (i < ' ' || i > 127 || _all)
{
ret += "\\x";
ret.push_back("0123456789abcdef"[(uint8_t)i / 16]);
ret.push_back("0123456789abcdef"[(uint8_t)i % 16]);
}
else
ret.push_back(i);
ret.push_back('"');
return ret;
}
std::string eth::randomWord()
{
static std::mt19937_64 s_eng(0);
std::string ret(std::uniform_int_distribution<int>(4, 10)(s_eng), ' ');
char const n[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
std::uniform_int_distribution<int> d(0, sizeof(n) - 2);
for (char& c: ret)
c = n[d(s_eng)];
return ret;
}
int eth::fromHex(char _i)
{
if (_i >= '0' && _i <= '9')
return _i - '0';
if (_i >= 'a' && _i <= 'f')
return _i - 'a' + 10;
if (_i >= 'A' && _i <= 'F')
return _i - 'A' + 10;
throw BadHexCharacter();
}
bytes eth::fromUserHex(std::string const& _s)
{
assert(_s.size() % 2 == 0);
if (_s.size() < 2)
return bytes();
uint s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s) / 2);
for (uint i = s; i < _s.size(); i += 2)
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
return ret;
}
bytes eth::toHex(std::string const& _s)
{
std::vector<uint8_t> ret;
ret.reserve(_s.size() * 2);
for (auto i: _s)
{
ret.push_back(i / 16);
ret.push_back(i % 16);
}
return ret;
}
std::string eth::sha3(std::string const& _input, bool _hex)
{
if (!_hex)
{
string ret(32, '\0');
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)ret.data(), 32));
return ret;
}
uint8_t buf[32];
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)&(buf[0]), 32));
std::string ret(64, '\0');
for (unsigned int i = 0; i < 32; i++)
sprintf((char*)(ret.data())+i*2, "%02x", buf[i]);
return ret;
}
void eth::sha3(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes eth::sha3Bytes(bytesConstRef _input)
{
bytes ret(32);
sha3(_input, &ret);
return ret;
}
h256 eth::sha3(bytesConstRef _input)
{
h256 ret;
sha3(_input, bytesRef(&ret[0], 32));
return ret;
}
Address eth::toAddress(Secret _private)
{
secp256k1_start();
byte pubkey[65];
int pubkeylen = 65;
int ok = secp256k1_ecdsa_seckey_verify(_private.data());
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0);
assert(pubkeylen == 65);
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return Address();
auto ret = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << _private << endl;
cout << "PUB: " << asHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl;
#endif
return ret;
}
KeyPair KeyPair::create()
{
secp256k1_start();
static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (unsigned i = 0; i < 32; ++i)
sec[i] = (byte)d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{
int ok = secp256k1_ecdsa_seckey_verify(m_secret.data());
if (!ok)
return;
byte pubkey[65];
int pubkeylen = 65;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0);
if (!ok || pubkeylen != 65)
return;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return;
m_secret = m_secret;
memcpy(m_public.data(), &(pubkey[1]), 64);
m_address = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
}
static const vector<pair<u256, string>> g_units =
{
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000, "Uether"},
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000, "Vether"},
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000, "Dether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000, "Nether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000, "Yether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000, "Zether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000000000, "Eether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000000, "Pether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000, "Tether"},
{(u256(1000000000) * 1000000000) * 1000000000, "Gether"},
{(u256(1000000000) * 1000000000) * 1000000, "Mether"},
{(u256(1000000000) * 1000000000) * 1000, "Kether"},
{u256(1000000000) * 1000000000, "ether"},
{u256(1000000000) * 1000000, "finney"},
{u256(1000000000) * 1000, "szabo"},
{u256(1000000000), "Gwei"},
{u256(1000000), "Mwei"},
{u256(1000), "Kwei"},
{u256(1), "wei"}
};
vector<pair<u256, string>> const& eth::units()
{
return g_units;
}
std::string eth::formatBalance(u256 _b)
{
ostringstream ret;
if (_b > g_units[0].first * 10000)
{
ret << (_b / g_units[0].first) << " " << g_units[0].second;
return ret.str();
}
ret << setprecision(5);
for (auto const& i: g_units)
if (i.first != 1 && _b >= i.first * 100)
{
ret << (double(_b / (i.first / 1000)) / 1000.0) << " " << i.second;
return ret.str();
}
ret << _b << " wei";
return ret.str();
}
bytes eth::contents(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
if (!is)
return bytes();
// get length of file:
is.seekg (0, is.end);
streamoff length = is.tellg();
is.seekg (0, is.beg);
bytes ret(length);
is.read((char*)ret.data(), length);
is.close();
return ret;
}
void eth::writeFile(std::string const& _file, bytes const& _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}

617
libethereum/Common.h

@ -18,13 +18,13 @@
* @author Gav Wood <i@gavwood.com> * @author Gav Wood <i@gavwood.com>
* @date 2014 * @date 2014
* *
* Shared algorithms and data types. * Very common stuff (i.e. that every other header needs except vector_ref.h).
*/ */
#pragma once #pragma once
// define version // define version
#define ETH_VERSION 0.4.0 #define ETH_VERSION 0.3.11
// way to many uint to size_t warnings in 32 bit build // way to many uint to size_t warnings in 32 bit build
#ifdef _M_IX86 #ifdef _M_IX86
@ -36,27 +36,16 @@
#define noexcept throw() #define noexcept throw()
#endif #endif
#include <ctime>
#include <chrono>
#include <array>
#include <map> #include <map>
#include <unordered_map> #include <vector>
#include <set> #include <set>
#include <array>
#include <list>
#include <set>
#include <string>
#include <cassert>
#include <sstream>
#include <cstdint>
#include <type_traits>
#include <boost/multiprecision/cpp_int.hpp> #include <boost/multiprecision/cpp_int.hpp>
#include <boost/thread.hpp>
#include "vector_ref.h" #include "vector_ref.h"
// CryptoPP defines byte in the global namespace, so so must we. // CryptoPP defines byte in the global namespace, so so must we.
using byte = uint8_t; using byte = uint8_t;
// Quote a given token stream to turn it into a string.
#define ETH_QUOTED_HELPER(s) #s #define ETH_QUOTED_HELPER(s) #s
#define ETH_QUOTED(s) ETH_QUOTED_HELPER(s) #define ETH_QUOTED(s) ETH_QUOTED_HELPER(s)
@ -81,132 +70,6 @@ using u160s = std::vector<u160>;
using u256Set = std::set<u256>; using u256Set = std::set<u256>;
using u160Set = std::set<u160>; using u160Set = std::set<u160>;
template <class T, class Out> inline void toBigEndian(T _val, Out& o_out);
template <class T, class In> inline T fromBigEndian(In const& _bytes);
/// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte.
/// @example asHex("A\x69") == "4169"
template <class _T>
std::string asHex(_T const& _data, int _w = 2)
{
std::ostringstream ret;
for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str();
}
/// Converts a (printable) ASCII hex string into the corresponding byte stream.
/// @example fromUserHex("41626261") == asBytes("Abba")
bytes fromUserHex(std::string const& _s);
template <unsigned T> class UnitTest {};
template <unsigned N>
class FixedHash
{
using Arith = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
public:
enum { size = N };
enum ConstructFromPointerType { ConstructFromPointer };
FixedHash() { m_data.fill(0); }
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
explicit FixedHash(bytes const& _b) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<uint>(_b.size(), N)); }
explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); }
explicit FixedHash(std::string const& _user): FixedHash(fromUserHex(_user)) {}
operator Arith() const { return fromBigEndian<Arith>(m_data); }
operator bool() const { return ((Arith)*this) != 0; }
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
bool operator<(FixedHash const& _c) const { return m_data < _c.m_data; }
FixedHash& operator^=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; }
FixedHash operator^(FixedHash const& _c) const { return FixedHash(*this) ^= _c; }
FixedHash& operator|=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] |= _c.m_data[i]; return *this; }
FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; }
FixedHash& operator&=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; }
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; }
std::string abridged() const { return asHex(ref().cropped(0, 4)) + ".."; }
byte& operator[](unsigned _i) { return m_data[_i]; }
byte operator[](unsigned _i) const { return m_data[_i]; }
bytesRef ref() { return bytesRef(m_data.data(), N); }
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
byte* data() { return m_data.data(); }
byte const* data() const { return m_data.data(); }
bytes asBytes() const { return bytes(data(), data() + N); }
std::array<byte, N>& asArray() { return m_data; }
std::array<byte, N> const& asArray() const { return m_data; }
// generic std::hash compatible function object
struct hash
{
size_t operator()(FixedHash const& value) const
{
size_t h = 0;
for (auto i: value.m_data)
h = (h << 5 - h) + i;
return h;
}
};
private:
std::array<byte, N> m_data;
};
// fast equality for h256
template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const
{
const uint64_t* hash1 = (const uint64_t*)this->data();
const uint64_t* hash2 = (const uint64_t*)_other.data();
return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]);
}
// fast std::hash compatible hash function object for h256
template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
{
const uint64_t*data = (const uint64_t*)value.data();
uint64_t hash = data[0];
hash ^= data[1];
hash ^= data[2];
hash ^= data[3];
return (size_t)hash;
}
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
{
_out << std::noshowbase << std::hex << std::setfill('0');
for (unsigned i = 0; i < N; ++i)
_out << std::setw(2) << (int)_h[i];
_out << std::dec;
return _out;
}
using h512 = FixedHash<64>;
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
using h256s = std::vector<h256>;
using h160s = std::vector<h160>;
using h256Set = std::set<h256>;
using h160Set = std::set<h160>;
using Secret = h256;
using Public = h512;
using Address = h160;
using Addresses = h160s;
// Map types. // Map types.
using StringMap = std::map<std::string, std::string>; using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>; using u256Map = std::map<u256, u256>;
@ -216,475 +79,7 @@ using HexMap = std::map<bytes, std::string>;
static const u256 Invalid256 = ~(u256)0; static const u256 Invalid256 = ~(u256)0;
static const bytes NullBytes; static const bytes NullBytes;
/// Logging /// Trivial UnitTest type that everyone can agree on, mainly to allow befriending for test classes & their code.
class NullOutputStream template <unsigned T> class UnitTest {};
{
public:
template <class T> NullOutputStream& operator<<(T const&) { return *this; }
};
extern std::map<std::type_info const*, bool> g_logOverride;
struct ThreadLocalLogName
{
ThreadLocalLogName(std::string _name) { m_name.reset(new std::string(_name)); };
boost::thread_specific_ptr<std::string> m_name;
};
extern ThreadLocalLogName t_logThreadName;
inline void setThreadName(char const* _n) { t_logThreadName.m_name.reset(new std::string(_n)); }
struct LogChannel { static const char* name() { return " "; } static const int verbosity = 1; };
struct LeftChannel: public LogChannel { static const char* name() { return "<<<"; } };
struct RightChannel: public LogChannel { static const char* name() { return ">>>"; } };
struct WarnChannel: public LogChannel { static const char* name() { return "!!!"; } static const int verbosity = 0; };
struct NoteChannel: public LogChannel { static const char* name() { return "***"; } };
struct DebugChannel: public LogChannel { static const char* name() { return "---"; } static const int verbosity = 0; };
extern int g_logVerbosity;
extern std::function<void(std::string const&, char const*)> g_logPost;
void simpleDebugOut(std::string const&, char const* );
template <class Id, bool _AutoSpacing = true>
class LogOutputStream
{
public:
LogOutputStream(bool _term = true)
{
std::type_info const* i = &typeid(Id);
auto it = g_logOverride.find(i);
if ((it != g_logOverride.end() && it->second == true) || (it == g_logOverride.end() && Id::verbosity <= g_logVerbosity))
{
time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char buf[24];
if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0)
buf[0] = '\0'; // empty if case strftime fails
sstr << Id::name() << " [ " << buf << " | " << *(t_logThreadName.m_name.get()) << (_term ? " ] " : "");
}
}
~LogOutputStream() { if (Id::verbosity <= g_logVerbosity) g_logPost(sstr.str(), Id::name()); }
template <class T> LogOutputStream& operator<<(T const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && sstr.str().size() && sstr.str().back() != ' ') sstr << " "; sstr << _t; } return *this; }
std::stringstream sstr;
};
// Dirties the global namespace, but oh so convenient...
#define cnote eth::LogOutputStream<eth::NoteChannel, true>()
#define cwarn eth::LogOutputStream<eth::WarnChannel, true>()
#define ndebug if (true) {} else eth::NullOutputStream()
#define nlog(X) if (true) {} else eth::NullOutputStream()
#define nslog(X) if (true) {} else eth::NullOutputStream()
#if NDEBUG
#define cdebug ndebug
#else
#define cdebug eth::LogOutputStream<eth::DebugChannel, true>()
#endif
#if NLOG
#define clog(X) nlog(X)
#define cslog(X) nslog(X)
#else
#define clog(X) eth::LogOutputStream<X, true>()
#define cslog(X) eth::LogOutputStream<X, false>()
#endif
/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(u256 _b);
/// Converts arbitrary value to string representation using std::stringstream.
template <class _T>
std::string toString(_T const& _t)
{
std::ostringstream o;
o << _t;
return o.str();
}
/// Converts byte array to a string containing the same (binary) data. Unless
/// the byte array happens to contain ASCII data, this won't be printable.
inline std::string asString(bytes const& _b)
{
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
}
/// Converts a string to a byte array containing the string's (byte) data.
inline bytes asBytes(std::string const& _b)
{
return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size()));
}
/// Trims a given number of elements from the front of a collection.
/// Only works for POD element types.
template <class _T>
void trimFront(_T& _t, uint _elements)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0]));
_t.resize(_t.size() - _elements);
}
/// Pushes an element on to the front of a collection.
/// Only works for POD element types.
template <class _T, class _U>
void pushFront(_T& _t, _U _e)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
_t.push_back(_e);
memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e));
_t[0] = _e;
}
/// Creates a random, printable, word.
std::string randomWord();
/// Escapes a string into the C-string representation.
/// @p _all if true will escape all characters, not just the unprintable ones.
std::string escaped(std::string const& _s, bool _all = true);
/// Converts a (printable) ASCII hex character into the correspnding integer value.
/// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5
int fromHex(char _i);
/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
/// @example toHex("A")[0] == 4 && toHex("A")[1] == 1
bytes toHex(std::string const& _s);
/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
/// The size of the collection object will be unchanged. If it is too small, it will not represent the
/// value properly, if too big then the additional elements will be zeroed out.
/// @a _Out will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
template <class _T, class _Out>
inline void toBigEndian(_T _val, _Out& o_out)
{
for (auto i = o_out.size(); i-- != 0; _val >>= 8)
o_out[i] = (typename _Out::value_type)(uint8_t)_val;
}
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
/// @a _In will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
template <class _T, class _In>
inline _T fromBigEndian(_In const& _bytes)
{
_T ret = 0;
for (auto i: _bytes)
ret = (ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i;
return ret;
}
/// Convenience functions for toBigEndian
inline std::string toBigEndianString(u256 _val) { std::string ret(32, '\0'); toBigEndian(_val, ret); return ret; }
inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
/// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val.
template <class _T>
inline std::string toCompactBigEndianString(_T _val)
{
int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {}
std::string ret(i, '\0');
toBigEndian(_val, ret);
return ret;
}
/// Determines the length of the common prefix of the two collections given.
/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
/// @example commonPrefix("Hello world!", "Hello, world!") == 5
template <class _T, class _U>
uint commonPrefix(_T const& _t, _U const& _u)
{
uint s = std::min<uint>(_t.size(), _u.size());
for (uint i = 0;; ++i)
if (i == s || _t[i] != _u[i])
return i;
return s;
}
/// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes.
inline h160 right160(h256 const& _t)
{
h160 ret;
memcpy(ret.data(), _t.data() + 12, 20);
return ret;
}
/// Convert the given value into h160 (160-bit unsigned integer) using the left 20 bytes.
inline h160 left160(h256 const& _t)
{
h160 ret;
memcpy(&ret[0], _t.data(), 20);
return ret;
}
/// Convert the given value into u160 (160-bit unsigned integer) by taking the lowest order 160-bits and discarding the rest.
inline u160 low160(u256 const& _t)
{
return (u160)(_t & ((((u256)1) << 160) - 1));
}
inline u160 low160(bigint const& _t)
{
return (u160)(_t & ((((bigint)1) << 160) - 1));
}
/// Convert the given value into u160 (160-bit unsigned integer) by taking the lowest order 160-bits and discarding the rest.
inline u160 high160(u256 const& _t)
{
return (u160)(_t >> 96);
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b)
{
auto s = _a.size();
_a.resize(_a.size() + _b.size());
memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(_T));
return _a;
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T> operator+(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type> const& _a, std::vector<_T> const& _b)
{
std::vector<_T> ret(_a);
return ret += _b;
}
/// SHA-3 convenience routines.
void sha3(bytesConstRef _input, bytesRef _output);
std::string sha3(std::string const& _input, bool _hex);
bytes sha3Bytes(bytesConstRef _input);
inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); }
inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); }
h256 sha3(bytesConstRef _input);
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); }
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
/// Get information concerning the currency denominations.
std::vector<std::pair<u256, std::string>> const& units();
/// Convert a private key into the public key equivalent.
/// @returns 0 if it's not a valid private key.
Address toAddress(h256 _private);
class KeyPair
{
public:
KeyPair() {}
KeyPair(Secret _k);
static KeyPair create();
Secret const& secret() const { return m_secret; }
Secret const& sec() const { return m_secret; }
Public const& pub() const { return m_public; }
Address const& address() const { return m_address; }
private:
Secret m_secret;
Public m_public;
Address m_address;
};
static const u256 Uether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Vether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Dether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Nether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Yether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Zether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Eether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Pether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Tether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Gether = (u256(1000000000) * 1000000000) * 1000000000;
static const u256 Mether = (u256(1000000000) * 1000000000) * 1000000;
static const u256 Kether = (u256(1000000000) * 1000000000) * 1000;
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
static const u256 Gwei = u256(1000000000);
static const u256 Mwei = u256(1000000);
static const u256 Kwei = u256(1000);
static const u256 wei = u256(1);
// Stream IO
template <class S, class T> struct StreamOut { static S& bypass(S& _out, T const& _t) { _out << _t; return _out; } };
template <class S> struct StreamOut<S, uint8_t> { static S& bypass(S& _out, uint8_t const& _t) { _out << (int)_t; return _out; } };
template <class S, class T>
inline S& streamout(S& _out, std::vector<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
for (auto i = ++_e.begin(); i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::vector<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned long Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned long Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
inline S& streamout(S& _out, std::list<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
_out << _e.front();
for (auto i = ++_e.begin(); i != _e.end(); ++i)
_out << "," << *i;
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::list<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
inline S& streamout(S& _out, std::pair<T, U> const& _e)
{
_out << "(" << _e.first << "," << _e.second << ")";
return _out;
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::pair<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T1, class T2, class T3>
inline S& streamout(S& _out, std::tuple<T1, T2, T3> const& _t)
{
_out << "(" << std::get<0>(_t) << "," << std::get<1>(_t) << "," << std::get<2>(_t) << ")";
return _out;
}
template <class T1, class T2, class T3> inline std::ostream& operator<<(std::ostream& _out, std::tuple<T1, T2, T3> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::unordered_map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::unordered_map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::set<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::set<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::multiset<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::multiset<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::multimap<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
T l;
int i = 0;
for (auto p: _v)
if (!(i++))
_out << "{ " << (l = p.first) << " => " << p.second;
else if (l == p.first)
_out << ", " << p.second;
else
_out << "; " << (l = p.first) << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p) { if (_p) _out << "@" << (*_p); else _out << "nullptr"; return _out; }
bytes contents(std::string const& _file);
void writeFile(std::string const& _file, bytes const& _data);
}
namespace std
{
// forward std::hash<eth::h256> to eth::h256::hash
template<> struct hash<eth::h256>: eth::h256::hash {};
} }

96
libethereum/CommonData.cpp

@ -0,0 +1,96 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "CommonData.h"
#include <random>
#include "Exceptions.h"
using namespace std;
using namespace eth;
std::string eth::escaped(std::string const& _s, bool _all)
{
std::string ret;
ret.reserve(_s.size());
ret.push_back('"');
for (auto i: _s)
if (i == '"' && !_all)
ret += "\\\"";
else if (i == '\\' && !_all)
ret += "\\\\";
else if (i < ' ' || i > 127 || _all)
{
ret += "\\x";
ret.push_back("0123456789abcdef"[(uint8_t)i / 16]);
ret.push_back("0123456789abcdef"[(uint8_t)i % 16]);
}
else
ret.push_back(i);
ret.push_back('"');
return ret;
}
std::string eth::randomWord()
{
static std::mt19937_64 s_eng(0);
std::string ret(std::uniform_int_distribution<int>(4, 10)(s_eng), ' ');
char const n[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
std::uniform_int_distribution<int> d(0, sizeof(n) - 2);
for (char& c: ret)
c = n[d(s_eng)];
return ret;
}
int eth::fromHex(char _i)
{
if (_i >= '0' && _i <= '9')
return _i - '0';
if (_i >= 'a' && _i <= 'f')
return _i - 'a' + 10;
if (_i >= 'A' && _i <= 'F')
return _i - 'A' + 10;
throw BadHexCharacter();
}
bytes eth::fromHex(std::string const& _s)
{
assert(_s.size() % 2 == 0);
if (_s.size() < 2)
return bytes();
uint s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s) / 2);
for (uint i = s; i < _s.size(); i += 2)
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
return ret;
}
bytes eth::asNibbles(std::string const& _s)
{
std::vector<uint8_t> ret;
ret.reserve(_s.size() * 2);
for (auto i: _s)
{
ret.push_back(i / 16);
ret.push_back(i % 16);
}
return ret;
}

186
libethereum/CommonData.h

@ -0,0 +1,186 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Shared algorithms and data types.
*/
#pragma once
#include <vector>
#include <algorithm>
#include <type_traits>
#include <cstring>
#include <string>
#include "Common.h"
namespace eth
{
// String conversion functions, mainly to/from hex/nibble/byte representations.
/// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte.
/// @example toHex("A\x69") == "4169"
template <class _T>
std::string toHex(_T const& _data, int _w = 2)
{
std::ostringstream ret;
for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str();
}
/// Converts a (printable) ASCII hex character into the correspnding integer value.
/// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5
int fromHex(char _i);
/// Converts a (printable) ASCII hex string into the corresponding byte stream.
/// @example fromHex("41626261") == asBytes("Abba")
bytes fromHex(std::string const& _s);
/// Converts byte array to a string containing the same (binary) data. Unless
/// the byte array happens to contain ASCII data, this won't be printable.
inline std::string asString(bytes const& _b)
{
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
}
/// Converts a string to a byte array containing the string's (byte) data.
inline bytes asBytes(std::string const& _b)
{
return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size()));
}
/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
/// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1
bytes asNibbles(std::string const& _s);
// Big-endian to/from host endian conversion functions.
/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
/// The size of the collection object will be unchanged. If it is too small, it will not represent the
/// value properly, if too big then the additional elements will be zeroed out.
/// @a _Out will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
template <class _T, class _Out>
inline void toBigEndian(_T _val, _Out& o_out)
{
for (auto i = o_out.size(); i-- != 0; _val >>= 8)
o_out[i] = (typename _Out::value_type)(uint8_t)_val;
}
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
/// @a _In will typically be either std::string or bytes.
/// @a _T will typically by uint, u160, u256 or bigint.
template <class _T, class _In>
inline _T fromBigEndian(_In const& _bytes)
{
_T ret = 0;
for (auto i: _bytes)
ret = (ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i;
return ret;
}
/// Convenience functions for toBigEndian
inline std::string toBigEndianString(u256 _val) { std::string ret(32, '\0'); toBigEndian(_val, ret); return ret; }
inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
/// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val.
template <class _T>
inline std::string toCompactBigEndianString(_T _val)
{
int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {}
std::string ret(i, '\0');
toBigEndian(_val, ret);
return ret;
}
// Algorithms for string and string-like collections.
/// Escapes a string into the C-string representation.
/// @p _all if true will escape all characters, not just the unprintable ones.
std::string escaped(std::string const& _s, bool _all = true);
/// Determines the length of the common prefix of the two collections given.
/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
/// @example commonPrefix("Hello world!", "Hello, world!") == 5
template <class _T, class _U>
uint commonPrefix(_T const& _t, _U const& _u)
{
uint s = std::min<uint>(_t.size(), _u.size());
for (uint i = 0;; ++i)
if (i == s || _t[i] != _u[i])
return i;
return s;
}
/// Creates a random, printable, word.
std::string randomWord();
// General datatype convenience functions.
/// Trims a given number of elements from the front of a collection.
/// Only works for POD element types.
template <class _T>
void trimFront(_T& _t, uint _elements)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0]));
_t.resize(_t.size() - _elements);
}
/// Pushes an element on to the front of a collection.
/// Only works for POD element types.
template <class _T, class _U>
void pushFront(_T& _t, _U _e)
{
static_assert(std::is_pod<typename _T::value_type>::value, "");
_t.push_back(_e);
memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e));
_t[0] = _e;
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b)
{
auto s = _a.size();
_a.resize(_a.size() + _b.size());
memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(_T));
return _a;
}
/// Concatenate two vectors of elements. _T must be POD.
template <class _T>
inline std::vector<_T> operator+(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type> const& _a, std::vector<_T> const& _b)
{
std::vector<_T> ret(_a);
return ret += _b;
}
}

200
libethereum/CommonEth.cpp

@ -0,0 +1,200 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CommonEth.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "CommonEth.h"
#if WIN32
#pragma warning(push)
#pragma warning(disable:4244)
#else
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#include <secp256k1.h>
#include <sha3.h>
#if WIN32
#pragma warning(pop)
#else
#endif
#include "Exceptions.h"
using namespace std;
using namespace eth;
//#define ETH_ADDRESS_DEBUG 1
static const vector<pair<u256, string>> g_units =
{
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000, "Uether"},
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000, "Vether"},
{((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000, "Dether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000, "Nether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000, "Yether"},
{(((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000, "Zether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000000000, "Eether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000000, "Pether"},
{((u256(1000000000) * 1000000000) * 1000000000) * 1000, "Tether"},
{(u256(1000000000) * 1000000000) * 1000000000, "Gether"},
{(u256(1000000000) * 1000000000) * 1000000, "Mether"},
{(u256(1000000000) * 1000000000) * 1000, "Kether"},
{u256(1000000000) * 1000000000, "ether"},
{u256(1000000000) * 1000000, "finney"},
{u256(1000000000) * 1000, "szabo"},
{u256(1000000000), "Gwei"},
{u256(1000000), "Mwei"},
{u256(1000), "Kwei"},
{u256(1), "wei"}
};
vector<pair<u256, string>> const& eth::units()
{
return g_units;
}
std::string eth::formatBalance(u256 _b)
{
ostringstream ret;
if (_b > g_units[0].first * 10000)
{
ret << (_b / g_units[0].first) << " " << g_units[0].second;
return ret.str();
}
ret << setprecision(5);
for (auto const& i: g_units)
if (i.first != 1 && _b >= i.first * 100)
{
ret << (double(_b / (i.first / 1000)) / 1000.0) << " " << i.second;
return ret.str();
}
ret << _b << " wei";
return ret.str();
}
Address eth::toAddress(Secret _private)
{
secp256k1_start();
byte pubkey[65];
int pubkeylen = 65;
int ok = secp256k1_ecdsa_seckey_verify(_private.data());
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0);
assert(pubkeylen == 65);
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return Address();
auto ret = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << _private << endl;
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl;
#endif
return ret;
}
KeyPair KeyPair::create()
{
secp256k1_start();
static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (unsigned i = 0; i < 32; ++i)
sec[i] = (byte)d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{
int ok = secp256k1_ecdsa_seckey_verify(m_secret.data());
if (!ok)
return;
byte pubkey[65];
int pubkeylen = 65;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0);
if (!ok || pubkeylen != 65)
return;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return;
m_secret = m_secret;
memcpy(m_public.data(), &(pubkey[1]), 64);
m_address = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
}
std::string eth::sha3(std::string const& _input, bool _hex)
{
if (!_hex)
{
string ret(32, '\0');
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)ret.data(), 32));
return ret;
}
uint8_t buf[32];
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)&(buf[0]), 32));
std::string ret(64, '\0');
for (unsigned int i = 0; i < 32; i++)
sprintf((char*)(ret.data())+i*2, "%02x", buf[i]);
return ret;
}
void eth::sha3(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes eth::sha3Bytes(bytesConstRef _input)
{
bytes ret(32);
sha3(_input, &ret);
return ret;
}
h256 eth::sha3(bytesConstRef _input)
{
h256 ret;
sha3(_input, bytesRef(&ret[0], 32));
return ret;
}

137
libethereum/CommonEth.h

@ -0,0 +1,137 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CommonEth.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Ethereum-specific data structures & algorithms.
*/
#pragma once
#include "Common.h"
#include "FixedHash.h"
namespace eth
{
/// A secret key: 32 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Secret = h256;
/// A public key: 64 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Public = h512;
/// An Ethereum address: 20 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Address = h160;
/// A vector of Ethereum addresses.
using Addresses = h160s;
/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(u256 _b);
/// Get information concerning the currency denominations.
std::vector<std::pair<u256, std::string>> const& units();
// The various denominations; here for ease of use where needed within code.
static const u256 Uether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Vether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Dether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Nether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Yether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Zether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Eether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Pether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Tether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Gether = (u256(1000000000) * 1000000000) * 1000000000;
static const u256 Mether = (u256(1000000000) * 1000000000) * 1000000;
static const u256 Kether = (u256(1000000000) * 1000000000) * 1000;
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
static const u256 Gwei = u256(1000000000);
static const u256 Mwei = u256(1000000);
static const u256 Kwei = u256(1000);
static const u256 wei = u256(1);
/// Convert a private key into the public key equivalent.
/// @returns 0 if it's not a valid private key.
Address toAddress(h256 _private);
/// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone.
/// Actually stores a tuplet of secret, public and address (the right 160-bits of the public).
class KeyPair
{
public:
/// Null constructor.
KeyPair() {}
/// Normal constructor - populates object from the given secret key.
KeyPair(Secret _k);
/// Create a new, randomly generated object.
static KeyPair create();
/// Retrieve the secret key.
Secret const& secret() const { return m_secret; }
/// Retrieve the secret key.
Secret const& sec() const { return m_secret; }
/// Retrieve the public key.
Public const& pub() const { return m_public; }
/// Retrieve the associated address of the public key.
Address const& address() const { return m_address; }
private:
Secret m_secret;
Public m_public;
Address m_address;
};
// SHA-3 convenience routines.
/// Calculate SHA3-256 hash of the given input and load it into the given output.
void sha3(bytesConstRef _input, bytesRef _output);
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
std::string sha3(std::string const& _input, bool _isNibbles);
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
bytes sha3Bytes(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array.
inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
h256 sha3(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
}

48
libethereum/CommonIO.cpp

@ -0,0 +1,48 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CommonIO.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Common.h"
#include <fstream>
#include "Exceptions.h"
using namespace std;
using namespace eth;
bytes eth::contents(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
if (!is)
return bytes();
// get length of file:
is.seekg (0, is.end);
streamoff length = is.tellg();
is.seekg (0, is.beg);
bytes ret(length);
is.read((char*)ret.data(), length);
is.close();
return ret;
}
void eth::writeFile(std::string const& _file, bytes const& _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}

223
libethereum/CommonIO.h

@ -0,0 +1,223 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CommonIO.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* File & stream I/O routines.
*/
#pragma once
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <array>
#include <list>
#include <memory>
#include <vector>
#include <array>
#include <sstream>
#include <string>
#include <iostream>
#include "Common.h"
namespace eth
{
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
bytes contents(std::string const& _file);
/// Write the given binary data into the given file, replacing the file if it pre-exists.
void writeFile(std::string const& _file, bytes const& _data);
/// Converts arbitrary value to string representation using std::stringstream.
template <class _T>
std::string toString(_T const& _t)
{
std::ostringstream o;
o << _t;
return o.str();
}
// Stream I/O functions.
// Provides templated stream I/O for all STL collections so they can be shifted on to any iostream-like interface.
template <class S, class T> struct StreamOut { static S& bypass(S& _out, T const& _t) { _out << _t; return _out; } };
template <class S> struct StreamOut<S, uint8_t> { static S& bypass(S& _out, uint8_t const& _t) { _out << (int)_t; return _out; } };
template <class S, class T>
inline S& streamout(S& _out, std::vector<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
for (auto i = ++_e.begin(); i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::vector<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned long Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned long Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
inline S& streamout(S& _out, std::list<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
_out << _e.front();
for (auto i = ++_e.begin(); i != _e.end(); ++i)
_out << "," << *i;
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::list<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
inline S& streamout(S& _out, std::pair<T, U> const& _e)
{
_out << "(" << _e.first << "," << _e.second << ")";
return _out;
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::pair<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T1, class T2, class T3>
inline S& streamout(S& _out, std::tuple<T1, T2, T3> const& _t)
{
_out << "(" << std::get<0>(_t) << "," << std::get<1>(_t) << "," << std::get<2>(_t) << ")";
return _out;
}
template <class T1, class T2, class T3> inline std::ostream& operator<<(std::ostream& _out, std::tuple<T1, T2, T3> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::unordered_map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::unordered_map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::set<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::set<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::unordered_set<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::unordered_set<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::multiset<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::multiset<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::multimap<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
T l;
int i = 0;
for (auto p: _v)
if (!(i++))
_out << "{ " << (l = p.first) << " => " << p.second;
else if (l == p.first)
_out << ", " << p.second;
else
_out << "; " << (l = p.first) << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p) { if (_p) _out << "@" << (*_p); else _out << "nullptr"; return _out; }
}

3
libethereum/Dagger.h

@ -23,7 +23,8 @@
#pragma once #pragma once
#include "Common.h" #include "FixedHash.h"
#include "CommonEth.h"
#define FAKE_DAGGER 1 #define FAKE_DAGGER 1

1
libethereum/Defaults.h

@ -36,6 +36,7 @@ public:
static Defaults* get() { if (!s_this) s_this = new Defaults; return s_this; } static Defaults* get() { if (!s_this) s_this = new Defaults; return s_this; }
static void setDBPath(std::string const& _dbPath) { get()->m_dbPath = _dbPath; } static void setDBPath(std::string const& _dbPath) { get()->m_dbPath = _dbPath; }
static std::string const& dbPath() { return get()->m_dbPath; }
private: private:
std::string m_dbPath; std::string m_dbPath;

12
libethereum/Exceptions.h

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <exception> #include <exception>
#include "Common.h" #include "CommonIO.h"
#include "CommonData.h"
#include "FixedHash.h"
namespace eth namespace eth
{ {
@ -31,13 +33,13 @@ class NoSuchContract: public Exception {};
class ContractAddressCollision: public Exception {}; class ContractAddressCollision: public Exception {};
class FeeTooSmall: public Exception {}; class FeeTooSmall: public Exception {};
class InvalidSignature: public Exception {}; class InvalidSignature: public Exception {};
class InvalidTransactionFormat: public Exception {}; class InvalidTransactionFormat: public Exception { public: InvalidTransactionFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid transaction format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidBlockFormat: public Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block format: Bad field " + toString(m_f) + " (" + asHex(m_d) + ")"; } }; class InvalidBlockFormat: public Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidBlockHeaderFormat: public Exception { public: InvalidBlockHeaderFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block header format: Bad field " + toString(m_f) + " (" + asHex(m_d) + ")"; } }; class InvalidBlockHeaderFormat: public Exception { public: InvalidBlockHeaderFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block header format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } };
class InvalidUnclesHash: public Exception {}; class InvalidUnclesHash: public Exception {};
class InvalidUncle: public Exception {}; class InvalidUncle: public Exception {};
class InvalidStateRoot: public Exception {}; class InvalidStateRoot: public Exception {};
class InvalidTransactionsHash: public Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual std::string description() const { return "Invalid transactions hash: header says: " + asHex(m_head.ref()) + " block is:" + asHex(m_real.ref()); } }; class InvalidTransactionsHash: public Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual std::string description() const { return "Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref()); } };
class InvalidTransaction: public Exception {}; class InvalidTransaction: public Exception {};
class InvalidDifficulty: public Exception {}; class InvalidDifficulty: public Exception {};
class InvalidTimestamp: public Exception {}; class InvalidTimestamp: public Exception {};

8
libethereum/FeeStructure.h

@ -26,11 +26,13 @@
namespace eth namespace eth
{ {
/**
* The collection of fee amounts that makes up the fee structure.
*/
struct FeeStructure struct FeeStructure
{ {
/// The fee structure. Values yet to be agreed on... void setMultiplier(u256 _x); ///< Set the current block multiplier.
void setMultiplier(u256 _x); ///< The current block multiplier. u256 multiplier() const; ///< @returns the current block multiplier.
u256 multiplier() const;
u256 m_stepFee; u256 m_stepFee;
u256 m_dataFee; u256 m_dataFee;
u256 m_memoryFee; u256 m_memoryFee;

25
libethereum/FixedHash.cpp

@ -0,0 +1,25 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FixedHash.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "FixedHash.h"
using namespace std;
using namespace eth;

195
libethereum/FixedHash.h

@ -0,0 +1,195 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FixedHash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The FixedHash fixed-size "hash" container type.
*/
#pragma once
#include <array>
#include <algorithm>
#include "CommonData.h"
namespace eth
{
/// Fixed-size raw-byte array container type, with an API optimised for storing hashes.
/// Transparently converts to/from the corresponding arithmetic type; this will
/// assume the data contained in the hash is big-endian.
template <unsigned N>
class FixedHash
{
/// The corresponding arithmetic type.
using Arith = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
public:
/// The size of the container.
enum { size = N };
/// A dummy flag to avoid accidental construction from pointer.
enum ConstructFromPointerType { ConstructFromPointer };
/// Method to convert from a string.
enum ConstructFromStringType { FromHex, FromBinary };
/// Construct an empty hash.
FixedHash() { m_data.fill(0); }
/// Convert from the corresponding arithmetic type.
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
/// Explicitly construct, copying from a byte array.
explicit FixedHash(bytes const& _b) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<uint>(_b.size(), N)); }
/// Explicitly construct, copying from a bytes in memory with given pointer.
explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); }
/// Explicitly construct, copying from a string.
explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex): FixedHash(_t == FromHex ? fromHex(_s) : eth::asBytes(_s)) {}
/// Convert to arithmetic type.
operator Arith() const { return fromBigEndian<Arith>(m_data); }
/// @returns true iff this is the empty hash.
operator bool() const { return ((Arith)*this) != 0; }
// The obvious comparison operators.
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
bool operator<(FixedHash const& _c) const { return m_data < _c.m_data; }
// The obvious binary operators.
FixedHash& operator^=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; }
FixedHash operator^(FixedHash const& _c) const { return FixedHash(*this) ^= _c; }
FixedHash& operator|=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] |= _c.m_data[i]; return *this; }
FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; }
FixedHash& operator&=(FixedHash const& _c) { for (auto i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; }
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; }
/// @returns a particular byte from the hash.
byte& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash.
byte operator[](unsigned _i) const { return m_data[_i]; }
/// @returns an abridged version of the hash as a user-readable hex string.
std::string abridged() const { return toHex(ref().cropped(0, 4)) + ".."; }
/// @returns a mutable byte vector_ref to the object's data.
bytesRef ref() { return bytesRef(m_data.data(), N); }
/// @returns a constant byte vector_ref to the object's data.
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
/// @returns a mutable byte pointer to the object's data.
byte* data() { return m_data.data(); }
/// @returns a constant byte pointer to the object's data.
byte const* data() const { return m_data.data(); }
/// @returns a copy of the object's data as a byte vector.
bytes asBytes() const { return bytes(data(), data() + N); }
/// @returns a mutable reference to the object's data as an STL array.
std::array<byte, N>& asArray() { return m_data; }
/// @returns a constant reference to the object's data as an STL array.
std::array<byte, N> const& asArray() const { return m_data; }
/// A generic std::hash compatible function object.
struct hash
{
/// Make a hash of the object's data.
size_t operator()(FixedHash const& value) const
{
size_t h = 0;
for (auto i: value.m_data)
h = (h << 5 - h) + i;
return h;
}
};
private:
std::array<byte, N> m_data; ///< The binary data.
};
/// Fast equality operator for h256.
template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const
{
const uint64_t* hash1 = (const uint64_t*)this->data();
const uint64_t* hash2 = (const uint64_t*)_other.data();
return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]);
}
/// Fast std::hash compatible hash function object for h256.
template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
{
const uint64_t*data = (const uint64_t*)value.data();
uint64_t hash = data[0];
hash ^= data[1];
hash ^= data[2];
hash ^= data[3];
return (size_t)hash;
}
/// Stream I/O for the FixedHash class.
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
{
_out << std::noshowbase << std::hex << std::setfill('0');
for (unsigned i = 0; i < N; ++i)
_out << std::setw(2) << (int)_h[i];
_out << std::dec;
return _out;
}
// Common types of FixedHash.
using h512 = FixedHash<64>;
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
using h256s = std::vector<h256>;
using h160s = std::vector<h160>;
using h256Set = std::set<h256>;
using h160Set = std::set<h160>;
/// Convert the given value into h160 (160-bit unsigned integer) using the right 20 bytes.
inline h160 right160(h256 const& _t)
{
h160 ret;
memcpy(ret.data(), _t.data() + 12, 20);
return ret;
}
/// Convert the given value into h160 (160-bit unsigned integer) using the left 20 bytes.
inline h160 left160(h256 const& _t)
{
h160 ret;
memcpy(&ret[0], _t.data(), 20);
return ret;
}
}
namespace std
{
/// Forward std::hash<eth::h256> to eth::h256::hash.
template<> struct hash<eth::h256>: eth::h256::hash {};
}

3
libethereum/Instruction.cpp

@ -22,7 +22,8 @@
#include "Instruction.h" #include "Instruction.h"
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "Common.h" #include "CommonEth.h"
#include "Log.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;

16
libethereum/Instruction.h

@ -84,14 +84,16 @@ enum class Instruction: uint8_t
SUICIDE = 0x3f SUICIDE = 0x3f
}; };
/// Information structure for a particular instruction.
struct InstructionInfo struct InstructionInfo
{ {
std::string name; std::string name; ///< The name of the instruction.
int additional; int additional; ///< Additional items required in memory for this instructions (only for PUSH).
int args; int args; ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack).
int ret; int ret; ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed.
}; };
/// Information on all the instructions.
static const std::map<Instruction, InstructionInfo> c_instructionInfo = static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ {
{ Instruction::STOP, { "STOP", 0, 0, 0 } }, { Instruction::STOP, { "STOP", 0, 0, 0 } },
@ -147,6 +149,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} } { Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} }
}; };
/// Convert from string mnemonic to Instruction type.
static const std::map<std::string, Instruction> c_instructions = static const std::map<std::string, Instruction> c_instructions =
{ {
{ "STOP", Instruction::STOP }, { "STOP", Instruction::STOP },
@ -202,8 +205,13 @@ static const std::map<std::string, Instruction> c_instructions =
{ "SUICIDE", Instruction::SUICIDE } { "SUICIDE", Instruction::SUICIDE }
}; };
/// Convert from simple EVM assembly language to EVM code.
u256s assemble(std::string const& _code, bool _quiet = false); u256s assemble(std::string const& _code, bool _quiet = false);
/// Convert from EVM code to simple EVM assembly language.
std::string disassemble(u256s const& _mem); std::string disassemble(u256s const& _mem);
/// Compile a Low-level Lisp-like Language program into EVM-code.
u256s compileLisp(std::string const& _code, bool _quiet = false); u256s compileLisp(std::string const& _code, bool _quiet = false);
} }

41
libethereum/Log.cpp

@ -0,0 +1,41 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Log.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Log.h"
#include <string>
#include <iostream>
using namespace std;
using namespace eth;
// Logging
int eth::g_logVerbosity = 8;
map<type_info const*, bool> eth::g_logOverride;
ThreadLocalLogName eth::t_logThreadName("main");
void eth::simpleDebugOut(std::string const& _s, char const*)
{
cout << _s << endl << flush;
}
std::function<void(std::string const&, char const*)> eth::g_logPost = simpleDebugOut;

134
libethereum/Log.h

@ -0,0 +1,134 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Log.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The logging subsystem.
*/
#pragma once
#include <ctime>
#include <chrono>
#include <boost/thread.hpp>
#include "vector_ref.h"
namespace eth
{
/// The null output stream. Used when logging is disabled.
class NullOutputStream
{
public:
template <class T> NullOutputStream& operator<<(T const&) { return *this; }
};
/// A simple log-output function that prints log messages to stdout.
void simpleDebugOut(std::string const&, char const* );
/// The logging system's current verbosity.
extern int g_logVerbosity;
/// The current method that the logging system uses to output the log messages. Defaults to simpleDebugOut().
extern std::function<void(std::string const&, char const*)> g_logPost;
/// Map of Log Channel types to bool, false forces the channel to be disabled, true forces it to be enabled.
/// If a channel has no entry, then it will output as long as its verbosity (LogChannel::verbosity) is less than
/// or equal to the currently output verbosity (g_logVerbosity).
extern std::map<std::type_info const*, bool> g_logOverride;
/// Associate a name with each thread for nice logging.
struct ThreadLocalLogName
{
ThreadLocalLogName(std::string _name) { m_name.reset(new std::string(_name)); };
boost::thread_specific_ptr<std::string> m_name;
};
/// The current thread's name.
extern ThreadLocalLogName t_logThreadName;
/// Set the current thread's log name.
inline void setThreadName(char const* _n) { t_logThreadName.m_name.reset(new std::string(_n)); }
/// The default logging channels. Each has an associated verbosity and three-letter prefix (name() ).
/// Channels should inherit from LogChannel and define name() and verbosity.
struct LogChannel { static const char* name() { return " "; } static const int verbosity = 1; };
struct LeftChannel: public LogChannel { static const char* name() { return "<<<"; } };
struct RightChannel: public LogChannel { static const char* name() { return ">>>"; } };
struct WarnChannel: public LogChannel { static const char* name() { return "!!!"; } static const int verbosity = 0; };
struct NoteChannel: public LogChannel { static const char* name() { return "***"; } };
struct DebugChannel: public LogChannel { static const char* name() { return "---"; } static const int verbosity = 0; };
/// Logging class, iostream-like, that can be shifted to.
template <class Id, bool _AutoSpacing = true>
class LogOutputStream
{
public:
/// Construct a new object.
/// If _term is true the the prefix info is terminated with a ']' character; if not it ends only with a '|' character.
LogOutputStream(bool _term = true)
{
std::type_info const* i = &typeid(Id);
auto it = g_logOverride.find(i);
if ((it != g_logOverride.end() && it->second == true) || (it == g_logOverride.end() && Id::verbosity <= g_logVerbosity))
{
time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char buf[24];
if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0)
buf[0] = '\0'; // empty if case strftime fails
m_sstr << Id::name() << " [ " << buf << " | " << *(t_logThreadName.m_name.get()) << (_term ? " ] " : "");
}
}
/// Destructor. Posts the accrued log entry to the g_logPost function.
~LogOutputStream() { if (Id::verbosity <= g_logVerbosity) g_logPost(m_sstr.str(), Id::name()); }
/// Shift arbitrary data to the log. Spaces will be added between items as required.
template <class T> LogOutputStream& operator<<(T const& _t) { if (Id::verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; m_sstr << _t; } return *this; }
private:
std::stringstream m_sstr; ///< The accrued log entry.
};
// Simple cout-like stream objects for accessing common log channels.
// Dirties the global namespace, but oh so convenient...
#define cnote eth::LogOutputStream<eth::NoteChannel, true>()
#define cwarn eth::LogOutputStream<eth::WarnChannel, true>()
// Null stream-like objects.
#define ndebug if (true) {} else eth::NullOutputStream()
#define nlog(X) if (true) {} else eth::NullOutputStream()
#define nslog(X) if (true) {} else eth::NullOutputStream()
// Kill debugging log channel when we're in release mode.
#if NDEBUG
#define cdebug ndebug
#else
#define cdebug eth::LogOutputStream<eth::DebugChannel, true>()
#endif
// Kill all logs when when NLOG is defined.
#if NLOG
#define clog(X) nlog(X)
#define cslog(X) nslog(X)
#else
#define clog(X) eth::LogOutputStream<X, true>()
#define cslog(X) eth::LogOutputStream<X, false>()
#endif
}

1066
libethereum/PeerNetwork.cpp

File diff suppressed because it is too large

166
libethereum/PeerNetwork.h

@ -17,18 +17,18 @@
/** @file PeerNetwork.h /** @file PeerNetwork.h
* @author Gav Wood <i@gavwood.com> * @author Gav Wood <i@gavwood.com>
* @date 2014 * @date 2014
*
* Miscellanea required for the PeerServer/PeerSession classes.
*/ */
#pragma once #pragma once
#include <map> #include <string>
#include <memory>
#include <utility>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <thread> #include <chrono>
#include "RLP.h"
#include "Common.h" #include "Common.h"
#include "Log.h"
namespace ba = boost::asio; namespace ba = boost::asio;
namespace bi = boost::asio::ip; namespace bi = boost::asio::ip;
@ -37,8 +37,11 @@ namespace eth
bool isPrivateAddress(bi::address _addressToCheck); bool isPrivateAddress(bi::address _addressToCheck);
class Overlay;
class BlockChain; class BlockChain;
class TransactionQueue; class TransactionQueue;
class PeerServer;
class PeerSession;
struct NetWarn: public LogChannel { static const char* name() { return "!N!"; } static const int verbosity = 0; }; struct NetWarn: public LogChannel { static const char* name() { return "!N!"; } static const int verbosity = 0; };
struct NetNote: public LogChannel { static const char* name() { return "*N*"; } static const int verbosity = 1; }; struct NetNote: public LogChannel { static const char* name() { return "*N*"; } static const int verbosity = 1; };
@ -76,7 +79,8 @@ enum DisconnectReason
ClientQuit ClientQuit
}; };
class PeerServer; /// @returns the string form of the given disconnection reason.
std::string reasonOf(DisconnectReason _r);
struct PeerInfo struct PeerInfo
{ {
@ -86,60 +90,7 @@ struct PeerInfo
std::chrono::steady_clock::duration lastPing; std::chrono::steady_clock::duration lastPing;
}; };
class PeerSession: public std::enable_shared_from_this<PeerSession> class UPnP;
{
friend class PeerServer;
public:
PeerSession(PeerServer* _server, bi::tcp::socket _socket, uint _rNId, bi::address _peerAddress, unsigned short _peerPort = 0);
~PeerSession();
void start();
void disconnect(int _reason);
void ping();
bool isOpen() const { return m_socket.is_open(); }
bi::tcp::endpoint endpoint() const; ///< for other peers to connect to.
private:
void dropped();
void doRead();
void doWrite(std::size_t length);
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
static bool checkPacket(bytesConstRef _msg);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
void send(bytesConstRef _msg);
PeerServer* m_server;
bi::tcp::socket m_socket;
std::array<byte, 65536> m_data;
PeerInfo m_info;
Public m_id;
bytes m_incoming;
uint m_protocolVersion;
uint m_networkId;
uint m_reqNetworkId;
unsigned short m_listenPort; ///< Port that the remote client is listening on for connections. Useful for giving to peers.
uint m_caps;
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::time_point m_connect;
std::chrono::steady_clock::time_point m_disconnect;
uint m_rating;
bool m_requireTransactions;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
};
enum class NodeMode enum class NodeMode
{ {
@ -147,99 +98,4 @@ enum class NodeMode
PeerServer PeerServer
}; };
class UPnP;
class PeerServer
{
friend class PeerSession;
public:
/// Start server, listening for connections on the given port.
PeerServer(std::string const& _clientVersion, BlockChain const& _ch, uint _networkId, unsigned short _port, NodeMode _m = NodeMode::Full, std::string const& _publicAddress = std::string(), bool _upnp = true);
/// Start server, but don't listen.
PeerServer(std::string const& _clientVersion, uint _networkId, NodeMode _m = NodeMode::Full);
~PeerServer();
/// Connect to a peer explicitly.
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
void connect(bi::tcp::endpoint const& _ep);
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
bool sync(BlockChain& _bc, TransactionQueue&, Overlay& _o);
bool sync();
/// Conduct I/O, polling, syncing, whatever.
/// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway.
/// This won't touch alter the blockchain.
void process() { if (isInitialised()) m_ioService.poll(); }
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
void setMode(NodeMode _m) { m_mode = _m; }
/// Get peer information.
std::vector<PeerInfo> peers() const;
/// Get number of peers connected; equivalent to, but faster than, peers().size().
size_t peerCount() const { return m_peers.size(); }
/// Ping the peers, to update the latency information.
void pingAll();
/// Get the port we're listening on currently.
unsigned short listenPort() const { return m_public.port(); }
bytes savePeers() const;
void restorePeers(bytesConstRef _b);
private:
void seal(bytes& _b);
void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp);
void ensureAccepting();
/// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return m_latestBlockSent; }
/// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first.
bool ensureInitialised(BlockChain& _bc, TransactionQueue& _tq);
std::map<Public, bi::tcp::endpoint> potentialPeers();
std::string m_clientVersion;
NodeMode m_mode = NodeMode::Full;
unsigned short m_listenPort;
BlockChain const* m_chain = nullptr;
ba::io_service m_ioService;
bi::tcp::acceptor m_acceptor;
bi::tcp::socket m_socket;
UPnP* m_upnp = nullptr;
bi::tcp::endpoint m_public;
KeyPair m_key;
uint m_requiredNetworkId;
std::map<Public, std::weak_ptr<PeerSession>> m_peers;
std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
std::vector<bytes> m_unknownParentBlocks;
std::vector<Public> m_freePeers;
std::map<Public, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers;
h256 m_latestBlockSent;
std::set<h256> m_transactionsSent;
std::chrono::steady_clock::time_point m_lastPeersRequest;
unsigned m_idealPeerCount = 5;
std::vector<bi::address_v4> m_addresses;
std::vector<bi::address_v4> m_peerAddresses;
bool m_accepting = false;
};
} }

542
libethereum/PeerServer.cpp

@ -0,0 +1,542 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file PeerNetwork.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* Eric Lombrozo <elombrozo@gmail.com>
* @date 2014
*/
#include "PeerServer.h"
#include <sys/types.h>
#ifdef _WIN32
// winsock is already included
// #include <winsock.h>
#else
#include <ifaddrs.h>
#endif
#include <set>
#include <chrono>
#include <thread>
#include "Exceptions.h"
#include "Common.h"
#include "BlockChain.h"
#include "BlockInfo.h"
#include "TransactionQueue.h"
#include "UPnP.h"
#include "PeerSession.h"
using namespace std;
using namespace eth;
// Addresses we will skip during network interface discovery
// Use a vector as the list is small
// Why this and not names?
// Under MacOSX loopback (127.0.0.1) can be named lo0 and br0 are bridges (0.0.0.0)
static const set<bi::address> c_rejectAddresses = {
{bi::address_v4::from_string("127.0.0.1")},
{bi::address_v6::from_string("::1")},
{bi::address_v4::from_string("0.0.0.0")},
{bi::address_v6::from_string("::")}
};
PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch, uint _networkId, unsigned short _port, NodeMode _m, string const& _publicAddress, bool _upnp):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(_port),
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_networkId(_networkId)
{
populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (_m == NodeMode::PeerServer ? "PeerServer" : "Full");
}
PeerServer::PeerServer(std::string const& _clientVersion, uint _networkId, NodeMode _m):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(0),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_networkId(_networkId)
{
// populate addresses.
populateAddresses();
clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (m_mode == NodeMode::PeerServer ? "PeerServer" : "Full");
}
PeerServer::~PeerServer()
{
for (auto const& i: m_peers)
if (auto p = i.second.lock())
p->disconnect(ClientQuit);
delete m_upnp;
}
unsigned PeerServer::protocolVersion()
{
return 8;
}
void PeerServer::determinePublic(string const& _publicAddress, bool _upnp)
{
if (_upnp)
try
{
m_upnp = new UPnP;
}
catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly.
bi::tcp::resolver r(m_ioService);
if (m_upnp && m_upnp->isValid() && m_peerAddresses.size())
{
clog(NetNote) << "External addr: " << m_upnp->externalIP();
int p = m_upnp->addRedirect(m_peerAddresses[0].to_string().c_str(), m_listenPort);
if (p)
clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << ".";
else
{
// couldn't map
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place). Assuming " << m_listenPort << " is local & external port.";
p = m_listenPort;
}
auto eip = m_upnp->externalIP();
if (eip == string("0.0.0.0") && _publicAddress.empty())
m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p);
else
{
m_public = bi::tcp::endpoint(bi::address::from_string(_publicAddress.empty() ? eip : _publicAddress), (unsigned short)p);
m_addresses.push_back(m_public.address().to_v4());
}
}
else
{
// No UPnP - fallback on given public address or, if empty, the assumed peer address.
m_public = bi::tcp::endpoint(_publicAddress.size() ? bi::address::from_string(_publicAddress)
: m_peerAddresses.size() ? m_peerAddresses[0]
: bi::address(), m_listenPort);
m_addresses.push_back(m_public.address().to_v4());
}
}
void PeerServer::populateAddresses()
{
#ifdef _WIN32
WSAData wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
throw NoNetworking();
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name.";
WSACleanup();
throw NoNetworking();
}
struct hostent* phe = gethostbyname(ac);
if (phe == 0)
{
clog(NetWarn) << "Bad host lookup.";
WSACleanup();
throw NoNetworking();
}
for (int i = 0; phe->h_addr_list[i] != 0; ++i)
{
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
char *addrStr = inet_ntoa(addr);
bi::address ad(bi::address::from_string(addrStr));
m_addresses.push_back(ad.to_v4());
bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
if (!isLocal)
m_peerAddresses.push_back(ad.to_v4());
clog(NetNote) << "Address: " << ac << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
}
WSACleanup();
#else
ifaddrs* ifaddr;
if (getifaddrs(&ifaddr) == -1)
throw NoNetworking();
bi::tcp::resolver r(m_ioService);
for (ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next)
{
if (!ifa->ifa_addr)
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
char host[NI_MAXHOST];
if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
continue;
// TODO: Make exception safe when no internet.
auto it = r.resolve({host, "30303"});
bi::tcp::endpoint ep = it->endpoint();
bi::address ad = ep.address();
m_addresses.push_back(ad.to_v4());
bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
if (!isLocal)
m_peerAddresses.push_back(ad.to_v4());
clog(NetNote) << "Address: " << host << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
}
}
freeifaddrs(ifaddr);
#endif
}
std::map<Public, bi::tcp::endpoint> PeerServer::potentialPeers()
{
std::map<Public, bi::tcp::endpoint> ret;
if (!m_public.address().is_unspecified())
ret.insert(make_pair(m_key.pub(), m_public));
for (auto i: m_peers)
if (auto j = i.second.lock())
{
auto ep = j->endpoint();
// Skip peers with a listen port of zero or are on a private network
bool peerOnNet = (j->m_listenPort != 0 && !isPrivateAddress(ep.address()));
if (peerOnNet && ep.port() && j->m_id)
ret.insert(make_pair(i.first, ep));
}
return ret;
}
void PeerServer::ensureAccepting()
{
if (m_accepting == false)
{
clog(NetNote) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")";
m_accepting = true;
m_acceptor.async_accept(m_socket, [=](boost::system::error_code ec)
{
if (!ec)
try
{
try {
clog(NetNote) << "Accepted connection from " << m_socket.remote_endpoint();
} catch (...){}
bi::address remoteAddress = m_socket.remote_endpoint().address();
// Port defaults to 0 - we let the hello tell us which port the peer listens to
auto p = std::make_shared<PeerSession>(this, std::move(m_socket), m_networkId, remoteAddress);
p->start();
}
catch (std::exception const& _e)
{
clog(NetWarn) << "ERROR: " << _e.what();
}
m_accepting = false;
if (ec.value() != 1 && (m_mode == NodeMode::PeerServer || m_peers.size() < m_idealPeerCount * 2))
ensureAccepting();
});
}
}
void PeerServer::connect(std::string const& _addr, unsigned short _port) noexcept
{
try
{
connect(bi::tcp::endpoint(bi::address::from_string(_addr), _port));
}
catch (exception const& e)
{
// Couldn't connect
clog(NetNote) << "Bad host " << _addr << " (" << e.what() << ")";
}
}
void PeerServer::connect(bi::tcp::endpoint const& _ep)
{
clog(NetNote) << "Attempting connection to " << _ep;
bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
s->async_connect(_ep, [=](boost::system::error_code const& ec)
{
if (ec)
{
clog(NetNote) << "Connection refused to " << _ep << " (" << ec.message() << ")";
for (auto i = m_incomingPeers.begin(); i != m_incomingPeers.end(); ++i)
if (i->second.first == _ep && i->second.second < 3)
{
m_freePeers.push_back(i->first);
goto OK;
}
// for-else
clog(NetNote) << "Giving up.";
OK:;
}
else
{
auto p = make_shared<PeerSession>(this, std::move(*s), m_networkId, _ep.address(), _ep.port());
clog(NetNote) << "Connected to " << _ep;
p->start();
}
delete s;
});
}
bool PeerServer::sync()
{
bool ret = false;
if (isInitialised())
for (auto i = m_peers.begin(); i != m_peers.end();)
{
auto p = i->second.lock();
if (p && p->m_socket.is_open() &&
(p->m_disconnect == chrono::steady_clock::time_point::max() || chrono::steady_clock::now() - p->m_disconnect < chrono::seconds(1))) // kill old peers that should be disconnected.
++i;
else
{
i = m_peers.erase(i);
ret = true;
}
}
return ret;
}
bool PeerServer::ensureInitialised(BlockChain& _bc, TransactionQueue& _tq)
{
if (m_latestBlockSent == h256())
{
// First time - just initialise.
m_latestBlockSent = _bc.currentHash();
clog(NetNote) << "Initialising: latest=" << m_latestBlockSent;
for (auto const& i: _tq.transactions())
m_transactionsSent.insert(i.first);
m_lastPeersRequest = chrono::steady_clock::time_point::min();
return true;
}
return false;
}
bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
{
bool ret = ensureInitialised(_bc, _tq);
if (sync())
ret = true;
if (m_mode == NodeMode::Full)
{
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
if (_tq.import(*it))
{}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
else
m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on.
m_incomingTransactions.clear();
auto h = _bc.currentHash();
bool resendAll = (h != m_latestBlockSent);
// Send any new transactions.
for (auto j: m_peers)
if (auto p = j.second.lock())
{
bytes b;
uint n = 0;
for (auto const& i: _tq.transactions())
if ((!m_transactionsSent.count(i.first) && !p->m_knownTransactions.count(i.first)) || p->m_requireTransactions || resendAll)
{
b += i.second;
++n;
m_transactionsSent.insert(i.first);
}
if (n)
{
RLPStream ts;
PeerSession::prep(ts);
ts.appendList(n + 1) << TransactionsPacket;
ts.appendRaw(b, n).swapOut(b);
seal(b);
p->send(&b);
}
p->m_knownTransactions.clear();
p->m_requireTransactions = false;
}
// Send any new blocks.
if (h != m_latestBlockSent)
{
// TODO: find where they diverge and send complete new branch.
RLPStream ts;
PeerSession::prep(ts);
ts.appendList(2) << BlocksPacket;
bytes b;
ts.appendRaw(_bc.block(_bc.currentHash())).swapOut(b);
seal(b);
for (auto j: m_peers)
if (auto p = j.second.lock())
{
if (!p->m_knownBlocks.count(_bc.currentHash()))
p->send(&b);
p->m_knownBlocks.clear();
}
}
m_latestBlockSent = h;
for (int accepted = 1, n = 0; accepted; ++n)
{
accepted = 0;
if (m_incomingBlocks.size())
for (auto it = prev(m_incomingBlocks.end());; --it)
{
try
{
_bc.import(*it, _o);
it = m_incomingBlocks.erase(it);
++accepted;
ret = true;
}
catch (UnknownParent)
{
// Don't (yet) know its parent. Leave it for later.
m_unknownParentBlocks.push_back(*it);
it = m_incomingBlocks.erase(it);
}
catch (...)
{
// Some other error - erase it.
it = m_incomingBlocks.erase(it);
}
if (it == m_incomingBlocks.begin())
break;
}
if (!n && accepted)
{
for (auto i: m_unknownParentBlocks)
m_incomingBlocks.push_back(i);
m_unknownParentBlocks.clear();
}
}
// Connect to additional peers
while (m_peers.size() < m_idealPeerCount)
{
if (m_freePeers.empty())
{
if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
{
RLPStream s;
bytes b;
(PeerSession::prep(s).appendList(1) << GetPeersPacket).swapOut(b);
seal(b);
for (auto const& i: m_peers)
if (auto p = i.second.lock())
if (p->isOpen())
p->send(&b);
m_lastPeersRequest = chrono::steady_clock::now();
}
if (!m_accepting)
ensureAccepting();
break;
}
auto x = time(0) % m_freePeers.size();
m_incomingPeers[m_freePeers[x]].second++;
connect(m_incomingPeers[m_freePeers[x]].first);
m_freePeers.erase(m_freePeers.begin() + x);
}
}
// platform for consensus of social contract.
// restricts your freedom but does so fairly. and that's the value proposition.
// guarantees that everyone else respect the rules of the system. (i.e. obeys laws).
// We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there.
for (uint old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
while (m_peers.size() > m_idealPeerCount)
{
// look for worst peer to kick off
// first work out how many are old enough to kick off.
shared_ptr<PeerSession> worst;
unsigned agedPeers = 0;
for (auto i: m_peers)
if (auto p = i.second.lock())
if ((m_mode != NodeMode::PeerServer || p->m_caps != 0x01) && chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
{
++agedPeers;
if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect))) // kill older ones
worst = p;
}
if (!worst || agedPeers <= m_idealPeerCount)
break;
worst->disconnect(TooManyPeers);
}
return ret;
}
std::vector<PeerInfo> PeerServer::peers() const
{
const_cast<PeerServer*>(this)->pingAll();
this_thread::sleep_for(chrono::milliseconds(200));
std::vector<PeerInfo> ret;
for (auto& i: m_peers)
if (auto j = i.second.lock())
if (j->m_socket.is_open())
ret.push_back(j->m_info);
return ret;
}
void PeerServer::pingAll()
{
for (auto& i: m_peers)
if (auto j = i.second.lock())
j->ping();
}
bytes PeerServer::savePeers() const
{
RLPStream ret;
int n = 0;
for (auto& i: m_peers)
if (auto p = i.second.lock())
if (p->m_socket.is_open() && p->endpoint().port())
{
ret.appendList(3) << p->endpoint().address().to_v4().to_bytes() << p->endpoint().port() << p->m_id;
n++;
}
return RLPStream(n).appendRaw(ret.out(), n).out();
}
void PeerServer::restorePeers(bytesConstRef _b)
{
for (auto i: RLP(_b))
{
auto k = (Public)i[2];
if (!m_incomingPeers.count(k))
{
m_incomingPeers.insert(make_pair(k, make_pair(bi::tcp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>()), 0)));
m_freePeers.push_back(k);
}
}
}

133
libethereum/PeerServer.h

@ -0,0 +1,133 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file PeerServer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <map>
#include <vector>
#include <set>
#include <memory>
#include <utility>
#include <thread>
#include "PeerNetwork.h"
#include "CommonEth.h"
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
namespace eth
{
class PeerServer
{
friend class PeerSession;
public:
/// Start server, listening for connections on the given port.
PeerServer(std::string const& _clientVersion, BlockChain const& _ch, uint _networkId, unsigned short _port, NodeMode _m = NodeMode::Full, std::string const& _publicAddress = std::string(), bool _upnp = true);
/// Start server, but don't listen.
PeerServer(std::string const& _clientVersion, uint _networkId, NodeMode _m = NodeMode::Full);
~PeerServer();
static unsigned protocolVersion();
unsigned networkId() { return m_networkId; }
/// Connect to a peer explicitly.
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
void connect(bi::tcp::endpoint const& _ep);
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
bool sync(BlockChain& _bc, TransactionQueue&, Overlay& _o);
bool sync();
/// Conduct I/O, polling, syncing, whatever.
/// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway.
/// This won't touch alter the blockchain.
void process() { if (isInitialised()) m_ioService.poll(); }
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
void setMode(NodeMode _m) { m_mode = _m; }
/// Get peer information.
std::vector<PeerInfo> peers() const;
/// Get number of peers connected; equivalent to, but faster than, peers().size().
size_t peerCount() const { return m_peers.size(); }
/// Ping the peers, to update the latency information.
void pingAll();
/// Get the port we're listening on currently.
unsigned short listenPort() const { return m_public.port(); }
bytes savePeers() const;
void restorePeers(bytesConstRef _b);
private:
void seal(bytes& _b);
void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp);
void ensureAccepting();
/// Check to see if the network peer-state initialisation has happened.
bool isInitialised() const { return m_latestBlockSent; }
/// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first.
bool ensureInitialised(BlockChain& _bc, TransactionQueue& _tq);
std::map<Public, bi::tcp::endpoint> potentialPeers();
std::string m_clientVersion;
NodeMode m_mode = NodeMode::Full;
unsigned short m_listenPort;
BlockChain const* m_chain = nullptr;
ba::io_service m_ioService;
bi::tcp::acceptor m_acceptor;
bi::tcp::socket m_socket;
UPnP* m_upnp = nullptr;
bi::tcp::endpoint m_public;
KeyPair m_key;
unsigned m_networkId;
std::map<Public, std::weak_ptr<PeerSession>> m_peers;
std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
std::vector<bytes> m_unknownParentBlocks;
std::vector<Public> m_freePeers;
std::map<Public, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers;
h256 m_latestBlockSent;
std::set<h256> m_transactionsSent;
std::chrono::steady_clock::time_point m_lastPeersRequest;
unsigned m_idealPeerCount = 5;
std::vector<bi::address_v4> m_addresses;
std::vector<bi::address_v4> m_peerAddresses;
bool m_accepting = false;
};
}

585
libethereum/PeerSession.cpp

@ -0,0 +1,585 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file PeerSession.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "PeerSession.h"
#include <chrono>
#include "Exceptions.h"
#include "Common.h"
#include "BlockChain.h"
#include "BlockInfo.h"
#include "PeerServer.h"
using namespace std;
using namespace eth;
#define clogS(X) eth::LogOutputStream<X, true>(false) << "| " << std::setw(2) << m_socket.native_handle() << "] "
static const eth::uint c_maxHashes = 32; ///< Maximum number of hashes GetChain will ever send.
static const eth::uint c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong.
static const eth::uint c_maxBlocksAsk = 256; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
PeerSession::PeerSession(PeerServer* _s, bi::tcp::socket _socket, uint _rNId, bi::address _peerAddress, unsigned short _peerPort):
m_server(_s),
m_socket(std::move(_socket)),
m_reqNetworkId(_rNId),
m_listenPort(_peerPort),
m_rating(0)
{
m_disconnect = std::chrono::steady_clock::time_point::max();
m_connect = std::chrono::steady_clock::now();
m_info = PeerInfo({"?", _peerAddress.to_string(), m_listenPort, std::chrono::steady_clock::duration(0)});
}
PeerSession::~PeerSession()
{
m_socket.close();
}
bi::tcp::endpoint PeerSession::endpoint() const
{
if (m_socket.is_open())
try {
return bi::tcp::endpoint(m_socket.remote_endpoint().address(), m_listenPort);
} catch (...){}
return bi::tcp::endpoint();
}
// TODO: BUG! 256 -> work out why things start to break with big packet sizes -> g.t. ~370 blocks.
bool PeerSession::interpret(RLP const& _r)
{
clogS(NetRight) << _r;
switch (_r[0].toInt<unsigned>())
{
case HelloPacket:
{
m_protocolVersion = _r[1].toInt<uint>();
m_networkId = _r[2].toInt<uint>();
auto clientVersion = _r[3].toString();
m_caps = _r[4].toInt<uint>();
m_listenPort = _r[5].toInt<unsigned short>();
m_id = _r[6].toHash<h512>();
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort;
if (m_server->m_peers.count(m_id))
if (auto l = m_server->m_peers[m_id].lock())
if (l.get() != this && l->isOpen())
{
// Already connected.
cwarn << "Already have peer id" << m_id.abridged() << "at" << l->endpoint() << "rather than" << endpoint();
disconnect(DuplicatePeer);
return false;
}
if (m_protocolVersion != PeerServer::protocolVersion() || m_networkId != m_server->networkId() || !m_id)
{
disconnect(IncompatibleProtocol);
return false;
}
try
{ m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), m_listenPort, std::chrono::steady_clock::duration()}); }
catch (...)
{
disconnect(BadProtocol);
return false;
}
m_server->m_peers[m_id] = shared_from_this();
// Grab their block chain off them.
{
clogS(NetAllDetail) << "Want chain. Latest:" << m_server->m_latestBlockSent << ", number:" << m_server->m_chain->details(m_server->m_latestBlockSent).number;
uint count = std::min(c_maxHashes, m_server->m_chain->details(m_server->m_latestBlockSent).number + 1);
RLPStream s;
prep(s).appendList(2 + count);
s << GetChainPacket;
auto h = m_server->m_latestBlockSent;
for (uint i = 0; i < count; ++i, h = m_server->m_chain->details(h).parent)
{
clogS(NetAllDetail) << " " << i << ":" << h;
s << h;
}
s << c_maxBlocksAsk;
sealAndSend(s);
s.clear();
prep(s).appendList(1);
s << GetTransactionsPacket;
sealAndSend(s);
}
break;
}
case DisconnectPacket:
{
string reason = "Unspecified";
if (_r[1].isInt())
reason = reasonOf((DisconnectReason)_r[1].toInt<int>());
clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
if (m_socket.is_open())
clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
else
clogS(NetNote) << "Remote closed.";
m_socket.close();
return false;
}
case PingPacket:
{
// clogS(NetMessageSummary) << "Ping";
RLPStream s;
sealAndSend(prep(s).appendList(1) << PongPacket);
break;
}
case PongPacket:
m_info.lastPing = std::chrono::steady_clock::now() - m_ping;
// clogS(NetMessageSummary) << "Latency: " << chrono::duration_cast<chrono::milliseconds>(m_lastPing).count() << " ms";
break;
case GetPeersPacket:
{
clogS(NetMessageSummary) << "GetPeers";
auto peers = m_server->potentialPeers();
RLPStream s;
prep(s).appendList(peers.size() + 1);
s << PeersPacket;
for (auto i: peers)
{
clogS(NetMessageDetail) << "Sending peer " << toHex(i.first.ref().cropped(0, 4)) << i.second;
s.appendList(3) << i.second.address().to_v4().to_bytes() << i.second.port() << i.first;
}
sealAndSend(s);
break;
}
case PeersPacket:
clogS(NetMessageSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)";
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
bi::address_v4 peerAddress(_r[i][0].toArray<byte, 4>());
auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt<short>());
Public id = _r[i][2].toHash<Public>();
if (isPrivateAddress(peerAddress))
goto CONTINUE;
clogS(NetAllDetail) << "Checking: " << ep << "(" << toHex(id.ref().cropped(0, 4)) << ")";
// check that it's not us or one we already know:
if (id && (m_server->m_key.pub() == id || m_server->m_peers.count(id) || m_server->m_incomingPeers.count(id)))
goto CONTINUE;
// check that we're not already connected to addr:
if (!ep.port())
goto CONTINUE;
for (auto i: m_server->m_addresses)
if (ep.address() == i && ep.port() == m_server->listenPort())
goto CONTINUE;
for (auto i: m_server->m_peers)
if (shared_ptr<PeerSession> p = i.second.lock())
{
clogS(NetAllDetail) << " ...against " << p->endpoint();
if (p->m_socket.is_open() && p->endpoint() == ep)
goto CONTINUE;
}
for (auto i: m_server->m_incomingPeers)
if (i.second.first == ep)
goto CONTINUE;
m_server->m_incomingPeers[id] = make_pair(ep, 0);
m_server->m_freePeers.push_back(id);
clogS(NetMessageDetail) << "New peer: " << ep << "(" << id << ")";
CONTINUE:;
}
break;
case TransactionsPacket:
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << " entries)";
m_rating += _r.itemCount() - 1;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
m_server->m_incomingTransactions.push_back(_r[i].data().toBytes());
m_knownTransactions.insert(sha3(_r[i].data()));
}
break;
case BlocksPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << " entries)";
unsigned used = 0;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = sha3(_r[i].data());
if (!m_server->m_chain->details(h))
{
m_server->m_incomingBlocks.push_back(_r[i].data().toBytes());
m_knownBlocks.insert(h);
used++;
}
}
m_rating += used;
if (g_logVerbosity >= 3)
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = sha3(_r[i].data());
BlockInfo bi(_r[i].data());
if (!m_server->m_chain->details(bi.parentHash) && !m_knownBlocks.count(bi.parentHash))
clogS(NetMessageDetail) << "Unknown parent " << bi.parentHash << " of block " << h;
else
clogS(NetMessageDetail) << "Known parent " << bi.parentHash << " of block " << h;
}
if (used) // we received some - check if there's any more
{
RLPStream s;
prep(s).appendList(3);
s << GetChainPacket;
s << sha3(_r[1].data());
s << c_maxBlocksAsk;
sealAndSend(s);
}
break;
}
case GetChainPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
clogS(NetMessageSummary) << "GetChain (" << (_r.itemCount() - 2) << " hashes, " << (_r[_r.itemCount() - 1].toInt<bigint>()) << ")";
// ********************************************************************
// NEEDS FULL REWRITE!
h256s parents;
parents.reserve(_r.itemCount() - 2);
for (unsigned i = 1; i < _r.itemCount() - 1; ++i)
parents.push_back(_r[i].toHash<h256>());
if (_r.itemCount() == 2)
break;
// return 2048 block max.
uint baseCount = (uint)min<bigint>(_r[_r.itemCount() - 1].toInt<bigint>(), c_maxBlocks);
clogS(NetMessageSummary) << "GetChain (" << baseCount << " max, from " << parents.front() << " to " << parents.back() << ")";
for (auto parent: parents)
{
auto h = m_server->m_chain->currentHash();
h256 latest = m_server->m_chain->currentHash();
uint latestNumber = 0;
uint parentNumber = 0;
RLPStream s;
if (m_server->m_chain->details(parent))
{
latestNumber = m_server->m_chain->details(latest).number;
parentNumber = m_server->m_chain->details(parent).number;
uint count = min<uint>(latestNumber - parentNumber, baseCount);
clogS(NetAllDetail) << "Requires " << dec << (latestNumber - parentNumber) << " blocks from " << latestNumber << " to " << parentNumber;
clogS(NetAllDetail) << latest << " - " << parent;
prep(s);
s.appendList(1 + count) << BlocksPacket;
uint endNumber = m_server->m_chain->details(parent).number;
uint startNumber = endNumber + count;
clogS(NetAllDetail) << "Sending " << dec << count << " blocks from " << startNumber << " to " << endNumber;
uint n = latestNumber;
for (; n > startNumber; n--, h = m_server->m_chain->details(h).parent) {}
for (uint i = 0; i < count; ++i, --n, h = m_server->m_chain->details(h).parent)
{
if (h == parent || n == endNumber)
{
cwarn << "BUG! Couldn't create the reply for GetChain!";
return true;
}
clogS(NetAllDetail) << " " << dec << i << " " << h;
s.appendRaw(m_server->m_chain->block(h));
}
clogS(NetAllDetail) << "Parent: " << h;
}
else if (parent != parents.back())
continue;
if (h != parent)
{
// not in the blockchain;
if (parent == parents.back())
{
// out of parents...
clogS(NetAllDetail) << "GetChain failed; not in chain";
// No good - must have been on a different branch.
s.clear();
prep(s).appendList(2) << NotInChainPacket << parents.back();
}
else
// still some parents left - try them.
continue;
}
// send the packet (either Blocks or NotInChain) & exit.
sealAndSend(s);
break;
// ********************************************************************
}
break;
}
case NotInChainPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
h256 noGood = _r[1].toHash<h256>();
clogS(NetMessageSummary) << "NotInChain (" << noGood << ")";
if (noGood == m_server->m_chain->genesisHash())
{
clogS(NetWarn) << "Discordance over genesis block! Disconnect.";
disconnect(WrongGenesis);
}
else
{
uint count = std::min(c_maxHashes, m_server->m_chain->details(noGood).number);
RLPStream s;
prep(s).appendList(2 + count);
s << GetChainPacket;
auto h = m_server->m_chain->details(noGood).parent;
for (uint i = 0; i < count; ++i, h = m_server->m_chain->details(h).parent)
s << h;
s << c_maxBlocksAsk;
sealAndSend(s);
}
break;
}
case GetTransactionsPacket:
{
if (m_server->m_mode == NodeMode::PeerServer)
break;
m_requireTransactions = true;
break;
}
default:
break;
}
return true;
}
void PeerSession::ping()
{
RLPStream s;
sealAndSend(prep(s).appendList(1) << PingPacket);
m_ping = std::chrono::steady_clock::now();
}
RLPStream& PeerSession::prep(RLPStream& _s)
{
return _s.appendRaw(bytes(8, 0));
}
void PeerServer::seal(bytes& _b)
{
_b[0] = 0x22;
_b[1] = 0x40;
_b[2] = 0x08;
_b[3] = 0x91;
uint32_t len = (uint32_t)_b.size() - 8;
_b[4] = (len >> 24) & 0xff;
_b[5] = (len >> 16) & 0xff;
_b[6] = (len >> 8) & 0xff;
_b[7] = len & 0xff;
}
void PeerSession::sealAndSend(RLPStream& _s)
{
bytes b;
_s.swapOut(b);
m_server->seal(b);
sendDestroy(b);
}
bool PeerSession::checkPacket(bytesConstRef _msg)
{
if (_msg.size() < 8)
return false;
if (!(_msg[0] == 0x22 && _msg[1] == 0x40 && _msg[2] == 0x08 && _msg[3] == 0x91))
return false;
uint32_t len = ((_msg[4] * 256 + _msg[5]) * 256 + _msg[6]) * 256 + _msg[7];
if (_msg.size() != len + 8)
return false;
RLP r(_msg.cropped(8));
if (r.actualSize() != len)
return false;
return true;
}
void PeerSession::sendDestroy(bytes& _msg)
{
clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8));
if (!checkPacket(bytesConstRef(&_msg)))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
}
auto self(shared_from_this());
bytes* buffer = new bytes(std::move(_msg));
ba::async_write(m_socket, ba::buffer(*buffer), [self, buffer](boost::system::error_code ec, std::size_t length)
{
delete buffer;
if (ec)
{
cwarn << "Error sending: " << ec.message();
self->dropped();
}
// cbug << length << " bytes written (EC: " << ec << ")";
});
}
void PeerSession::send(bytesConstRef _msg)
{
clogS(NetLeft) << RLP(_msg.cropped(8));
if (!checkPacket(_msg))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
}
auto self(shared_from_this());
bytes* buffer = new bytes(_msg.toBytes());
ba::async_write(m_socket, ba::buffer(*buffer), [self, buffer](boost::system::error_code ec, std::size_t length)
{
delete buffer;
if (ec)
{
cwarn << "Error sending: " << ec.message();
self->dropped();
}
// cbug << length << " bytes written (EC: " << ec << ")";
});
}
void PeerSession::dropped()
{
if (m_socket.is_open())
try {
clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
m_socket.close();
}catch (...){}
for (auto i = m_server->m_peers.begin(); i != m_server->m_peers.end(); ++i)
if (i->second.lock().get() == this)
{
m_server->m_peers.erase(i);
break;
}
}
void PeerSession::disconnect(int _reason)
{
clogS(NetNote) << "Disconnecting (reason:" << reasonOf((DisconnectReason)_reason) << ")";
if (m_socket.is_open())
{
if (m_disconnect == chrono::steady_clock::time_point::max())
{
RLPStream s;
prep(s);
s.appendList(2) << DisconnectPacket << _reason;
sealAndSend(s);
m_disconnect = chrono::steady_clock::now();
}
else
dropped();
}
}
void PeerSession::start()
{
RLPStream s;
prep(s);
s.appendList(7) << HelloPacket << (uint)PeerServer::protocolVersion() << m_server->networkId() << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port() << m_server->m_key.pub();
sealAndSend(s);
ping();
doRead();
}
void PeerSession::doRead()
{
auto self(shared_from_this());
m_socket.async_read_some(boost::asio::buffer(m_data), [this,self](boost::system::error_code ec, std::size_t length)
{
if (ec)
{
cwarn << "Error reading: " << ec.message();
dropped();
}
else
{
try
{
m_incoming.resize(m_incoming.size() + length);
memcpy(m_incoming.data() + m_incoming.size() - length, m_data.data(), length);
while (m_incoming.size() > 8)
{
if (m_incoming[0] != 0x22 || m_incoming[1] != 0x40 || m_incoming[2] != 0x08 || m_incoming[3] != 0x91)
{
clogS(NetWarn) << "Out of alignment.";
disconnect(BadProtocol);
return;
clogS(NetNote) << "Skipping: " << hex << showbase << (int)m_incoming[0] << dec;
memmove(m_incoming.data(), m_incoming.data() + 1, m_incoming.size() - 1);
m_incoming.resize(m_incoming.size() - 1);
}
else
{
uint32_t len = fromBigEndian<uint32_t>(bytesConstRef(m_incoming.data() + 4, 4));
uint32_t tlen = len + 8;
if (m_incoming.size() < tlen)
break;
// enough has come in.
// cerr << "Received " << len << ": " << toHex(bytesConstRef(m_incoming.data() + 8, len)) << endl;
auto data = bytesConstRef(m_incoming.data(), tlen);
if (!checkPacket(data))
{
cerr << "Received " << len << ": " << toHex(bytesConstRef(m_incoming.data() + 8, len)) << endl;
cwarn << "INVALID MESSAGE RECEIVED";
disconnect(BadProtocol);
return;
}
else
{
RLP r(data.cropped(8));
if (!interpret(r))
{
// error
dropped();
return;
}
}
memmove(m_incoming.data(), m_incoming.data() + tlen, m_incoming.size() - tlen);
m_incoming.resize(m_incoming.size() - tlen);
}
}
doRead();
}
catch (Exception const& _e)
{
clogS(NetWarn) << "ERROR: " << _e.description();
dropped();
}
catch (std::exception const& _e)
{
clogS(NetWarn) << "ERROR: " << _e.what();
dropped();
}
}
});
}

90
libethereum/PeerSession.h

@ -0,0 +1,90 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file PeerSession.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <array>
#include <set>
#include <memory>
#include <utility>
#include "RLP.h"
#include "CommonEth.h"
#include "PeerNetwork.h"
namespace eth
{
class PeerSession: public std::enable_shared_from_this<PeerSession>
{
friend class PeerServer;
public:
PeerSession(PeerServer* _server, bi::tcp::socket _socket, uint _rNId, bi::address _peerAddress, unsigned short _peerPort = 0);
~PeerSession();
void start();
void disconnect(int _reason);
void ping();
bool isOpen() const { return m_socket.is_open(); }
bi::tcp::endpoint endpoint() const; ///< for other peers to connect to.
private:
void dropped();
void doRead();
void doWrite(std::size_t length);
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
static bool checkPacket(bytesConstRef _msg);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
void send(bytesConstRef _msg);
PeerServer* m_server;
bi::tcp::socket m_socket;
std::array<byte, 65536> m_data;
PeerInfo m_info;
Public m_id;
bytes m_incoming;
uint m_protocolVersion;
uint m_networkId;
uint m_reqNetworkId;
unsigned short m_listenPort; ///< Port that the remote client is listening on for connections. Useful for giving to peers.
uint m_caps;
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::time_point m_connect;
std::chrono::steady_clock::time_point m_disconnect;
uint m_rating;
bool m_requireTransactions;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
};
}

53
libethereum/State.cpp

@ -42,10 +42,10 @@ std::map<Address, AddressState> const& eth::genesisState()
if (s_ret.empty()) if (s_ret.empty())
{ {
// Initialise. // Initialise.
s_ret[Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0, AddressType::Normal); s_ret[Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("e6716f9544a56c530d868e4bfbacb172315bdead"))] = AddressState(u256(1) << 200, 0, AddressType::Normal); s_ret[Address(fromHex("e6716f9544a56c530d868e4bfbacb172315bdead"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal); s_ret[Address(fromHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal); s_ret[Address(fromHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
} }
return s_ret; return s_ret;
} }
@ -55,6 +55,7 @@ Overlay State::openDB(std::string _path, bool _killExisting)
if (_path.empty()) if (_path.empty())
_path = Defaults::get()->m_dbPath; _path = Defaults::get()->m_dbPath;
boost::filesystem::create_directory(_path); boost::filesystem::create_directory(_path);
if (_killExisting) if (_killExisting)
boost::filesystem::remove_all(_path + "/state"); boost::filesystem::remove_all(_path + "/state");
@ -288,31 +289,41 @@ bool State::sync(TransactionQueue& _tq)
// TRANSACTIONS // TRANSACTIONS
bool ret = false; bool ret = false;
auto ts = _tq.transactions(); auto ts = _tq.transactions();
for (auto const& i: ts) vector<pair<h256, bytes>> futures;
for (int goodTxs = 1; goodTxs;)
{ {
if (!m_transactionSet.count(i.first)) goodTxs = 0;
for (auto const& i: ts)
{ {
// don't have it yet! Execute it now. if (!m_transactionSet.count(i.first))
try
{ {
execute(i.second); // don't have it yet! Execute it now.
ret = true; try
}
catch (InvalidNonce const& in)
{
if (in.required > in.candidate)
{ {
// too old execute(i.second);
ret = true;
_tq.noteGood(i);
++goodTxs;
}
catch (InvalidNonce const& in)
{
if (in.required > in.candidate)
{
// too old
_tq.drop(i.first);
ret = true;
}
else
_tq.setFuture(i);
}
catch (std::exception const&)
{
// Something else went wrong - drop it.
_tq.drop(i.first); _tq.drop(i.first);
ret = true; ret = true;
} }
} }
catch (std::exception const&)
{
// Something else went wrong - drop it.
_tq.drop(i.first);
ret = true;
}
} }
} }
return ret; return ret;

4
libethereum/State.h

@ -322,7 +322,7 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
std::map<u256, u256> mem; std::map<u256, u256> mem;
for (auto const& j: memdb) for (auto const& j: memdb)
{ {
_out << std::endl << " [" << j.first << ":" << asHex(j.second) << "]"; _out << std::endl << " [" << j.first << ":" << toHex(j.second) << "]";
#ifdef __clang__ #ifdef __clang__
auto mFinder = mem.find(j.first); auto mFinder = mem.find(j.first);
if (mFinder == mem.end()) if (mFinder == mem.end())
@ -359,7 +359,7 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
std::map<u256, u256> mem; std::map<u256, u256> mem;
for (auto const& j: memdb) for (auto const& j: memdb)
{ {
_out << std::endl << " [" << j.first << ":" << asHex(j.second) << "]"; _out << std::endl << " [" << j.first << ":" << toHex(j.second) << "]";
#ifdef __clang__ #ifdef __clang__
auto mFinder = mem.find(j.first); auto mFinder = mem.find(j.first);
if (mFinder == mem.end()) if (mFinder == mem.end())

24
libethereum/Transaction.cpp

@ -30,14 +30,22 @@ using namespace eth;
Transaction::Transaction(bytesConstRef _rlpData) Transaction::Transaction(bytesConstRef _rlpData)
{ {
int field = 0;
RLP rlp(_rlpData); RLP rlp(_rlpData);
nonce = rlp[0].toInt<u256>(); try
receiveAddress = rlp[1].toHash<Address>(); {
value = rlp[2].toInt<u256>(); nonce = rlp[field = 0].toInt<u256>();
data.reserve(rlp[3].itemCountStrict()); receiveAddress = rlp[field = 1].toHash<Address>();
for (auto const& i: rlp[3]) value = rlp[field = 2].toInt<u256>();
data.push_back(i.toInt<u256>()); data.reserve(rlp[field = 3].itemCountStrict());
vrs = Signature{ rlp[4].toInt<byte>(), rlp[5].toInt<u256>(), rlp[6].toInt<u256>() }; for (auto const& i: rlp[3])
data.push_back(i.toInt<u256>());
vrs = Signature{ rlp[field = 4].toInt<byte>(), rlp[field = 5].toInt<u256>(), rlp[field = 6].toInt<u256>() };
}
catch (RLPException const&)
{
throw InvalidTransactionFormat(field, rlp[field].data());
}
} }
Address Transaction::safeSender() const noexcept Address Transaction::safeSender() const noexcept
@ -71,7 +79,7 @@ Address Transaction::sender() const
cout << "---- RECOVER -------------------------------" << endl; cout << "---- RECOVER -------------------------------" << endl;
cout << "MSG: " << msg << endl; cout << "MSG: " << msg << endl;
cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(vrs.v - 27) << "+27" << endl; cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(vrs.v - 27) << "+27" << endl;
cout << "PUB: " << asHex(bytesConstRef(&(pubkey[1]), 64)) << endl; cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl; cout << "ADR: " << ret << endl;
#endif #endif
return ret; return ret;

2
libethereum/Transaction.h

@ -21,7 +21,7 @@
#pragma once #pragma once
#include "Common.h" #include "CommonEth.h"
#include "RLP.h" #include "RLP.h"
namespace eth namespace eth

25
libethereum/TransactionQueue.cpp

@ -19,6 +19,7 @@
* @date 2014 * @date 2014
*/ */
#include "Log.h"
#include "Transaction.h" #include "Transaction.h"
#include "TransactionQueue.h" #include "TransactionQueue.h"
using namespace std; using namespace std;
@ -43,11 +44,33 @@ bool TransactionQueue::import(bytes const& _block)
// If valid, append to blocks. // If valid, append to blocks.
m_data[h] = _block; m_data[h] = _block;
} }
catch (InvalidTransactionFormat const& _e)
{
cwarn << "Ignoring invalid transaction: " << _e.description();
return false;
}
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
cout << "*** Ignoring invalid transaction: " << _e.what(); cwarn << "Ignoring invalid transaction: " << _e.what();
return false; return false;
} }
return true; return true;
} }
void TransactionQueue::setFuture(std::pair<h256, bytes> const& _t)
{
if (m_data.count(_t.first))
{
m_data.erase(_t.first);
m_future.insert(make_pair(Transaction(_t.second).sender(), _t));
}
}
void TransactionQueue::noteGood(std::pair<h256, bytes> const& _t)
{
auto r = m_future.equal_range(Transaction(_t.second).sender());
for (auto it = r.first; it != r.second; ++it)
m_data.insert(_t);
m_future.erase(r.first, r.second);
}

6
libethereum/TransactionQueue.h

@ -40,14 +40,18 @@ public:
void drop(h256 _txHash) { m_data.erase(_txHash); } void drop(h256 _txHash) { m_data.erase(_txHash); }
std::map<h256, bytes> const& transactions() const { return m_data; } std::map<h256, bytes> const& transactions() const { return m_data; }
void setFuture(std::pair<h256, bytes> const& _t);
void noteGood(std::pair<h256, bytes> const& _t);
Transactions interestQueue() { Transactions ret; swap(ret, m_interestQueue); return ret; } Transactions interestQueue() { Transactions ret; swap(ret, m_interestQueue); return ret; }
void pushInterest(Address _a) { m_interest[_a]++; } void pushInterest(Address _a) { m_interest[_a]++; }
void popInterest(Address _a) { if (m_interest[_a] > 1) m_interest[_a]--; else if (m_interest[_a]) m_interest.erase(_a); } void popInterest(Address _a) { if (m_interest[_a] > 1) m_interest[_a]--; else if (m_interest[_a]) m_interest.erase(_a); }
private: private:
std::map<h256, bytes> m_data; ///< the queue. std::map<h256, bytes> m_data; ///< Map of SHA3(tx) to tx.
Transactions m_interestQueue; Transactions m_interestQueue;
std::map<Address, int> m_interest; std::map<Address, int> m_interest;
std::multimap<Address, std::pair<h256, bytes>> m_future; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
}; };
} }

6
libethereum/TrieDB.h

@ -25,6 +25,8 @@
#include <memory> #include <memory>
#include <leveldb/db.h> #include <leveldb/db.h>
#include "Exceptions.h" #include "Exceptions.h"
#include "CommonEth.h"
#include "Log.h"
#include "TrieCommon.h" #include "TrieCommon.h"
namespace ldb = leveldb; namespace ldb = leveldb;
@ -54,7 +56,7 @@ inline std::ostream& operator<<(std::ostream& _out, BasicMap const& _m)
{ {
_out << i.first << ": "; _out << i.first << ": ";
_out << RLP(i.second); _out << RLP(i.second);
_out << " " << asHex(i.second); _out << " " << toHex(i.second);
_out << std::endl; _out << std::endl;
} }
return _out; return _out;
@ -177,7 +179,7 @@ public:
} }
if (!(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17))) if (!(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17)))
{ {
cdebug << b.rlp.size() << asHex(b.rlp); cdebug << b.rlp.size() << toHex(b.rlp);
cdebug << rlp; cdebug << rlp;
auto c = rlp.itemCount(); auto c = rlp.itemCount();
cdebug << c; cdebug << c;

1
libethereum/UPnP.cpp

@ -26,6 +26,7 @@
#include <miniupnpc/miniupnpc.h> #include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h> #include <miniupnpc/upnpcommands.h>
#include "Common.h" #include "Common.h"
#include "Log.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "UPnP.h" #include "UPnP.h"
using namespace std; using namespace std;

8
libethereum/VM.h

@ -162,21 +162,29 @@ template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps)
break; break;
case Instruction::DIV: case Instruction::DIV:
require(2); require(2);
if (!m_stack[m_stack.size() - 2])
return;
m_stack[m_stack.size() - 2] = m_stack.back() / m_stack[m_stack.size() - 2]; m_stack[m_stack.size() - 2] = m_stack.back() / m_stack[m_stack.size() - 2];
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::SDIV: case Instruction::SDIV:
require(2); require(2);
if (!m_stack[m_stack.size() - 2])
return;
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() / (s256&)m_stack[m_stack.size() - 2]; (s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() / (s256&)m_stack[m_stack.size() - 2];
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::MOD: case Instruction::MOD:
require(2); require(2);
if (!m_stack[m_stack.size() - 2])
return;
m_stack[m_stack.size() - 2] = m_stack.back() % m_stack[m_stack.size() - 2]; m_stack[m_stack.size() - 2] = m_stack.back() % m_stack[m_stack.size() - 2];
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::SMOD: case Instruction::SMOD:
require(2); require(2);
if (!m_stack[m_stack.size() - 2])
return;
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() % (s256&)m_stack[m_stack.size() - 2]; (s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() % (s256&)m_stack[m_stack.size() - 2];
m_stack.pop_back(); m_stack.pop_back();
break; break;

8
package.sh

@ -1,8 +0,0 @@
#!/bin/bash
set -e
rm -f ../cpp-ethereum_*_source.changes
debuild -S -sa
cd ..
dput -f ppa:ethereum/ethereum cpp-ethereum_*_source.changes

65
release.sh

@ -1,65 +0,0 @@
#!/bin/bash
dist="saucy"
version=$(grep "define ETH_VERSION" libethereum/Common.h | cut -d ' ' -f 3)
branch="$(git branch | grep \* | cut -c 3-)"
if [[ ! "$1" == "" ]]; then
version=$1
fi
if [[ ! "$3" == "" ]]; then
if [[ ! "$4" == "" ]]; then
dist=$4
fi
if [[ "$2" == "-i" ]]; then
# increment current debian release only
# new version ./release VERSION -i MESSAGE DIST
debchange -i -p "$3" -D "$dist"
git commit -a -m "$3"
else
# new version ./release VERSION DEB-VERSION MESSAGE DIST
debchange -v $version-$2 -p "$3" -D "$dist"
git commit -a -m "$3"
fi
fi
opwd=`pwd`
cd /tmp
echo Checking out...
git clone $opwd
cd cpp-ethereum
git checkout "$branch"
archdir="cpp-ethereum-$version"
archfile="$archdir.tar.bz2"
echo Cleaning backup files...
find . | grep \~ | xargs rm -f
echo Cleaning others...
rm release.sh
echo Cleaning versioning...
rm -rf .git .gitignore
echo Renaming directory...
cd ..
rm -rf $archdir
mv cpp-ethereum $archdir
echo Creating archive...
tar c $archdir | bzip2 -- > $archfile
[[ ! "$version" == "" ]] && ln -sf $archfile "cpp-ethereum_$version.orig.tar.bz2"
echo Packaging...
cd "$archdir"
./package.sh
echo Cleaning up...
rm -rf /tmp/$archdir
mv /tmp/$archfile ~
echo Done.

15
libethereum/MemTrie.cpp → test/MemTrie.cpp

@ -19,9 +19,10 @@
* @date 2014 * @date 2014
*/ */
#include "Common.h"
#include "TrieCommon.h"
#include "MemTrie.h" #include "MemTrie.h"
#include <CommonEth.h>
#include <TrieCommon.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -147,7 +148,7 @@ public:
assert(m_value.size()); assert(m_value.size());
std::cerr << _indent; std::cerr << _indent;
if (m_ext.size()) if (m_ext.size())
std::cerr << asHex(m_ext, 1) << ": "; std::cerr << toHex(m_ext, 1) << ": ";
else else
std::cerr << "@: "; std::cerr << "@: ";
std::cerr << m_value << std::endl; std::cerr << m_value << std::endl;
@ -174,7 +175,7 @@ public:
#if ENABLE_DEBUG_PRINT #if ENABLE_DEBUG_PRINT
virtual void debugPrintBody(std::string const& _indent) const virtual void debugPrintBody(std::string const& _indent) const
{ {
std::cerr << _indent << asHex(m_ext, 1) << ": "; std::cerr << _indent << toHex(m_ext, 1) << ": ";
m_next->debugPrint(_indent + " "); m_next->debugPrint(_indent + " ");
} }
#endif #endif
@ -454,7 +455,7 @@ std::string const& MemTrie::at(std::string const& _key) const
{ {
if (!m_root) if (!m_root)
return c_nullString; return c_nullString;
auto h = toHex(_key); auto h = asNibbles(_key);
return m_root->at(bytesConstRef(&h)); return m_root->at(bytesConstRef(&h));
} }
@ -462,7 +463,7 @@ void MemTrie::insert(std::string const& _key, std::string const& _value)
{ {
if (_value.empty()) if (_value.empty())
remove(_key); remove(_key);
auto h = toHex(_key); auto h = asNibbles(_key);
m_root = m_root ? m_root->insert(&h, _value) : new TrieLeafNode(bytesConstRef(&h), _value); m_root = m_root ? m_root->insert(&h, _value) : new TrieLeafNode(bytesConstRef(&h), _value);
} }
@ -470,7 +471,7 @@ void MemTrie::remove(std::string const& _key)
{ {
if (m_root) if (m_root)
{ {
auto h = toHex(_key); auto h = asNibbles(_key);
m_root = m_root->remove(&h); m_root = m_root->remove(&h);
} }
} }

3
libethereum/MemTrie.h → test/MemTrie.h

@ -21,7 +21,8 @@
#pragma once #pragma once
#include "Common.h" #include <Common.h>
#include <FixedHash.h>
namespace eth namespace eth
{ {

15
libethereum/TrieHash.cpp → test/TrieHash.cpp

@ -19,9 +19,10 @@
* @date 2014 * @date 2014
*/ */
#include "Common.h"
#include "TrieCommon.h"
#include "TrieHash.h" #include "TrieHash.h"
#include <CommonEth.h>
#include <TrieCommon.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -58,7 +59,7 @@ void hash256rlp(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i
_rlp.appendList(2) << hexPrefixEncode(_begin->first, true, _preLen) << _begin->second; _rlp.appendList(2) << hexPrefixEncode(_begin->first, true, _preLen) << _begin->second;
#if ENABLE_DEBUG_PRINT #if ENABLE_DEBUG_PRINT
if (g_hashDebug) if (g_hashDebug)
std::cerr << s_indent << asHex(bytesConstRef(_begin->first.data() + _preLen, _begin->first.size() - _preLen), 1) << ": " << _begin->second << " = " << sha3(_rlp.out()) << std::endl; std::cerr << s_indent << toHex(bytesConstRef(_begin->first.data() + _preLen, _begin->first.size() - _preLen), 1) << ": " << _begin->second << " = " << sha3(_rlp.out()) << std::endl;
#endif #endif
} }
else else
@ -79,7 +80,7 @@ void hash256rlp(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i
// if they all have the same next nibble, we also want a pair. // if they all have the same next nibble, we also want a pair.
#if ENABLE_DEBUG_PRINT #if ENABLE_DEBUG_PRINT
if (g_hashDebug) if (g_hashDebug)
std::cerr << s_indent << asHex(bytesConstRef(_begin->first.data() + _preLen, sharedPre), 1) << ": " << std::endl; std::cerr << s_indent << toHex(bytesConstRef(_begin->first.data() + _preLen, sharedPre), 1) << ": " << std::endl;
#endif #endif
_rlp.appendList(2) << hexPrefixEncode(_begin->first, false, _preLen, (int)sharedPre); _rlp.appendList(2) << hexPrefixEncode(_begin->first, false, _preLen, (int)sharedPre);
hash256aux(_s, _begin, _end, (unsigned)sharedPre, _rlp); hash256aux(_s, _begin, _end, (unsigned)sharedPre, _rlp);
@ -162,7 +163,7 @@ h256 hash256(StringMap const& _s)
return h256(); return h256();
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second; hexMap[asNibbles(i->first)] = i->second;
RLPStream s; RLPStream s;
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return sha3(s.out()); return sha3(s.out());
@ -175,7 +176,7 @@ bytes rlp256(StringMap const& _s)
return bytes(); return bytes();
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second; hexMap[asNibbles(i->first)] = i->second;
RLPStream s; RLPStream s;
hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return s.out(); return s.out();
@ -188,7 +189,7 @@ h256 hash256(u256Map const& _s)
return h256(); return h256();
HexMap hexMap; HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i) for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(toBigEndianString(i->first))] = asString(rlp(i->second)); hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second));
RLPStream s; RLPStream s;
hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s);
return sha3(s.out()); return sha3(s.out());

3
libethereum/TrieHash.h → test/TrieHash.h

@ -21,7 +21,8 @@
#pragma once #pragma once
#include "Common.h" #include <Common.h>
#include <FixedHash.h>
namespace eth namespace eth
{ {

37
test/crypto.cpp

@ -24,6 +24,7 @@
#include <secp256k1.h> #include <secp256k1.h>
#include <Common.h> #include <Common.h>
#include <RLP.h> #include <RLP.h>
#include <Log.h>
#include <Transaction.h> #include <Transaction.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -33,21 +34,21 @@ int cryptoTest()
cnote << "Testing Crypto..."; cnote << "Testing Crypto...";
secp256k1_start(); secp256k1_start();
KeyPair p(Secret(fromUserHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4"))); KeyPair p(Secret(fromHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")));
assert(p.pub() == Public(fromUserHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f")));
assert(p.address() == Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075")));
{ {
Transaction t; Transaction t;
t.nonce = 0; t.nonce = 0;
t.receiveAddress = h160(fromUserHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000; t.value = 1000;
t.data = u256s(); t.data = u256s();
cnote << RLP(t.rlp(false)); cnote << RLP(t.rlp(false));
cnote << asHex(t.rlp(false)); cnote << toHex(t.rlp(false));
cnote << t.sha3(false); cnote << t.sha3(false);
t.sign(p.secret()); t.sign(p.secret());
cnote << RLP(t.rlp(true)); cnote << RLP(t.rlp(true));
cnote << asHex(t.rlp(true)); cnote << toHex(t.rlp(true));
cnote << t.sha3(true); cnote << t.sha3(true);
assert(t.sender() == p.address()); assert(t.sender() == p.address());
} }
@ -55,7 +56,7 @@ int cryptoTest()
#if 0 #if 0
// Test transaction. // Test transaction.
bytes tx = fromUserHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d"); bytes tx = fromHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d");
cout << "TX: " << RLP(tx) << endl; cout << "TX: " << RLP(tx) << endl;
Transaction t2(tx); Transaction t2(tx);
@ -69,13 +70,13 @@ int cryptoTest()
t.receiveAddress = toAddress(sha3("123")); t.receiveAddress = toAddress(sha3("123"));
bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s); bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s);
cout << "SIG: " << sig64.size() << " " << asHex(sig64) << " " << t.vrs.v << endl; cout << "SIG: " << sig64.size() << " " << toHex(sig64) << " " << t.vrs.v << endl;
auto msg = t.rlp(false); auto msg = t.rlp(false);
cout << "TX w/o SIG: " << RLP(msg) << endl; cout << "TX w/o SIG: " << RLP(msg) << endl;
cout << "RLP(TX w/o SIG): " << asHex(t.rlpString(false)) << endl; cout << "RLP(TX w/o SIG): " << toHex(t.rlpString(false)) << endl;
std::string hmsg = sha3(t.rlpString(false), false); std::string hmsg = sha3(t.rlpString(false), false);
cout << "SHA256(RLP(TX w/o SIG)): 0x" << asHex(hmsg) << endl; cout << "SHA256(RLP(TX w/o SIG)): 0x" << toHex(hmsg) << endl;
bytes privkey = sha3Bytes("123"); bytes privkey = sha3Bytes("123");
@ -84,12 +85,12 @@ int cryptoTest()
int pubkeylen = 65; int pubkeylen = 65;
int ret = secp256k1_ecdsa_seckey_verify(privkey.data()); int ret = secp256k1_ecdsa_seckey_verify(privkey.data());
cout << "SEC: " << dec << ret << " " << asHex(privkey) << endl; cout << "SEC: " << dec << ret << " " << toHex(privkey) << endl;
ret = secp256k1_ecdsa_pubkey_create(pubkey.data(), &pubkeylen, privkey.data(), 1); ret = secp256k1_ecdsa_pubkey_create(pubkey.data(), &pubkeylen, privkey.data(), 1);
pubkey.resize(pubkeylen); pubkey.resize(pubkeylen);
int good = secp256k1_ecdsa_pubkey_verify(pubkey.data(), (int)pubkey.size()); int good = secp256k1_ecdsa_pubkey_verify(pubkey.data(), (int)pubkey.size());
cout << "PUB: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << (good ? " GOOD" : " BAD") << endl; cout << "PUB: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << (good ? " GOOD" : " BAD") << endl;
} }
// Test roundtrip... // Test roundtrip...
@ -97,17 +98,17 @@ int cryptoTest()
bytes sig(64); bytes sig(64);
u256 nonce = 0; u256 nonce = 0;
int v = 0; int v = 0;
cout << asHex(hmsg) << endl; cout << toHex(hmsg) << endl;
cout << asHex(privkey) << endl; cout << toHex(privkey) << endl;
cout << hex << nonce << dec << endl; cout << hex << nonce << dec << endl;
int ret = secp256k1_ecdsa_sign_compact((byte const*)hmsg.data(), (int)hmsg.size(), sig.data(), privkey.data(), (byte const*)&nonce, &v); int ret = secp256k1_ecdsa_sign_compact((byte const*)hmsg.data(), (int)hmsg.size(), sig.data(), privkey.data(), (byte const*)&nonce, &v);
cout << "MYSIG: " << dec << ret << " " << sig.size() << " " << asHex(sig) << " " << v << endl; cout << "MYSIG: " << dec << ret << " " << sig.size() << " " << toHex(sig) << " " << v << endl;
bytes pubkey(65); bytes pubkey(65);
int pubkeylen = 65; int pubkeylen = 65;
ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig.data(), pubkey.data(), &pubkeylen, 0, v); ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig.data(), pubkey.data(), &pubkeylen, 0, v);
pubkey.resize(pubkeylen); pubkey.resize(pubkeylen);
cout << "MYREC: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl; cout << "MYREC: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << endl;
} }
{ {
@ -115,8 +116,8 @@ int cryptoTest()
int pubkeylen = 65; int pubkeylen = 65;
int ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 0, (int)t.vrs.v - 27); int ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 0, (int)t.vrs.v - 27);
pubkey.resize(pubkeylen); pubkey.resize(pubkeylen);
cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl; cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << endl;
cout << "SENDER: " << hex << low160(eth::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl; cout << "SENDER: " << hex << toAddress(eth::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl;
} }
#endif #endif
return 0; return 0;

1
test/dagger.cpp

@ -21,6 +21,7 @@
*/ */
#include <chrono> #include <chrono>
#include "Log.h"
#include "Dagger.h" #include "Dagger.h"
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;

7
test/hexPrefix.cpp

@ -24,6 +24,7 @@
#include "../json_spirit/json_spirit_reader_template.h" #include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h" #include "../json_spirit/json_spirit_writer_template.h"
#include "TrieCommon.h" #include "TrieCommon.h"
#include "Log.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
namespace js = json_spirit; namespace js = json_spirit;
@ -46,13 +47,13 @@ public:
cnote << i.first; cnote << i.first;
bytes v; bytes v;
for (auto& i: o["seq"].get_array()) for (auto& i: o["seq"].get_array())
v.push_back(i.get_int()); v.push_back((byte)i.get_int());
auto e = hexPrefixEncode(v, o["term"].get_bool()); auto e = hexPrefixEncode(v, o["term"].get_bool());
if (!o["out"].is_null() && o["out"].get_str() != asHex(e)) if (!o["out"].is_null() && o["out"].get_str() != toHex(e))
{ {
cwarn << "Test failed."; cwarn << "Test failed.";
cwarn << "Test says:" << o["out"].get_str(); cwarn << "Test says:" << o["out"].get_str();
cwarn << "Impl says:" << asHex(e); cwarn << "Impl says:" << toHex(e);
passed = false; passed = false;
} }
} }

2
test/main.cpp

@ -39,7 +39,7 @@ int main(int, char**)
/* RLPStream s; /* RLPStream s;
BlockInfo::genesis().fillStream(s, false); BlockInfo::genesis().fillStream(s, false);
std::cout << RLP(s.out()) << std::endl; std::cout << RLP(s.out()) << std::endl;
std::cout << asHex(s.out()) << std::endl; std::cout << toHex(s.out()) << std::endl;
std::cout << sha3(s.out()) << std::endl;*/ std::cout << sha3(s.out()) << std::endl;*/
int r = 0; int r = 0;

2
test/peer.cpp

@ -24,7 +24,7 @@
#include <thread> #include <thread>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <BlockChain.h> #include <BlockChain.h>
#include <PeerNetwork.h> #include <PeerServer.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
using boost::asio::ip::tcp; using boost::asio::ip::tcp;

5
test/rlp.cpp

@ -23,6 +23,7 @@
#include <fstream> #include <fstream>
#include "../json_spirit/json_spirit_reader_template.h" #include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h" #include "../json_spirit/json_spirit_writer_template.h"
#include <Log.h>
#include <RLP.h> #include <RLP.h>
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -67,11 +68,11 @@ public:
cnote << i.first; cnote << i.first;
RLPStream s; RLPStream s;
buildRLP(o["in"], s); buildRLP(o["in"], s);
if (!o["out"].is_null() && o["out"].get_str() != asHex(s.out())) if (!o["out"].is_null() && o["out"].get_str() != toHex(s.out()))
{ {
cwarn << "Test failed."; cwarn << "Test failed.";
cwarn << "Test says:" << o["out"].get_str(); cwarn << "Test says:" << o["out"].get_str();
cwarn << "Impl says:" << asHex(s.out()); cwarn << "Impl says:" << toHex(s.out());
passed = false; passed = false;
} }
} }

12
test/trie.cpp

@ -24,9 +24,9 @@
#include "../json_spirit/json_spirit_reader_template.h" #include "../json_spirit/json_spirit_reader_template.h"
#include "../json_spirit/json_spirit_writer_template.h" #include "../json_spirit/json_spirit_writer_template.h"
#include <random> #include <random>
#include <TrieHash.h>
#include <TrieDB.h> #include <TrieDB.h>
#include <MemTrie.h> #include "TrieHash.h"
#include "MemTrie.h"
using namespace std; using namespace std;
using namespace eth; using namespace eth;
@ -53,7 +53,7 @@ public:
vector<pair<string, string>> ss; vector<pair<string, string>> ss;
for (auto& i: o["in"].get_obj()) for (auto& i: o["in"].get_obj())
ss.push_back(make_pair(i.first, i.second.get_str())); ss.push_back(make_pair(i.first, i.second.get_str()));
for (unsigned j = 0; j < fac(ss.size()); ++j) for (unsigned j = 0; j < fac((unsigned)ss.size()); ++j)
{ {
next_permutation(ss.begin(), ss.end()); next_permutation(ss.begin(), ss.end());
BasicMap m; BasicMap m;
@ -61,11 +61,11 @@ public:
t.init(); t.init();
for (auto const& k: ss) for (auto const& k: ss)
t.insert(k.first, k.second); t.insert(k.first, k.second);
if (!o["root"].is_null() && o["root"].get_str() != asHex(t.root().asArray())) if (!o["root"].is_null() && o["root"].get_str() != toHex(t.root().asArray()))
{ {
cwarn << "Test failed on permutation " << j; cwarn << "Test failed on permutation " << j;
cwarn << "Test says:" << o["root"].get_str(); cwarn << "Test says:" << o["root"].get_str();
cwarn << "Impl says:" << asHex(t.root().asArray()); cwarn << "Impl says:" << toHex(t.root().asArray());
passed = false; passed = false;
} }
} }
@ -154,7 +154,7 @@ int trieTest()
t.insert("doe", "reindeer"); t.insert("doe", "reindeer");
cout << hex << t.hash256() << endl; cout << hex << t.hash256() << endl;
cout << RLP(t.rlp()) << endl; cout << RLP(t.rlp()) << endl;
cout << asHex(t.rlp()) << endl; cout << toHex(t.rlp()) << endl;
} }
{ {
BasicMap m; BasicMap m;

1
test/vm.cpp

@ -26,6 +26,7 @@
#include <ExtVMFace.h> #include <ExtVMFace.h>
#include <Transaction.h> #include <Transaction.h>
#include <VM.h> #include <VM.h>
#include <Log.h>
#include <Instruction.h> #include <Instruction.h>
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;

33
windows/Alethzero.vcxproj

@ -170,17 +170,17 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\alethzero\MainWin.h"> <CustomBuild Include="..\alethzero\MainWin.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(Lua)" moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)moc_%(FileName).cpp</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)moc_%(FileName).cpp</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</Message> </Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(Lua)" moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</Message> </Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(Lua)" moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</Message> </Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(Lua)" moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Lua) moc.lua "$(QtBin)/moc" "$(IntDir)moc_%(FileName).cpp" "@(ClCompile->'%(AdditionalIncludeDirectories)');$(IncludePath)" "@(ClCompile->'%(PreprocessorDefinitions)');_MSC_VER=1800" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</Message> </Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)moc_%(FileName).cpp</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)moc_%(FileName).cpp</Outputs>
@ -206,6 +206,31 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)ui_%(FileName).h</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)ui_%(FileName).h</Outputs>
</CustomBuild> </CustomBuild>
</ItemGroup> </ItemGroup>
<ItemGroup>
<CustomBuild Include="BuildInfo.lua">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Lua) "%(FullPath)" "$(IntDir)%(FileName).h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Lua) "%(FullPath)" "$(IntDir)%(FileName).h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Lua) "%(FullPath)" "$(IntDir)%(FileName).h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Lua) "%(FullPath)" "$(IntDir)%(FileName).h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(FileName).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(FileName).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(FileName).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(FileName).h</Outputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../.git/index</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../.git/index</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../.git/index</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../.git/index</AdditionalInputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

3
windows/Alethzero.vcxproj.filters

@ -24,5 +24,8 @@
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\alethzero\MainWin.h" /> <CustomBuild Include="..\alethzero\MainWin.h" />
<CustomBuild Include="..\alethzero\Main.ui" /> <CustomBuild Include="..\alethzero\Main.ui" />
<CustomBuild Include="BuildInfo.lua">
<Filter>Windows</Filter>
</CustomBuild>
</ItemGroup> </ItemGroup>
</Project> </Project>

25
windows/BuildInfo.lua

@ -0,0 +1,25 @@
function os.capture(cmd)
local f = io.popen(cmd, 'r')
if (f) then
local s = f:read('*a')
if (f:close()) then
return s
end
end
return nil
end
hash = (os.capture("git rev-parse HEAD") or "UnknownRevision"):gsub("\n$", "")
clean = ((os.capture("git diff --name-only") or "0"):gsub("\n$", "") == "") and "1" or "0"
local output = io.open(arg[1], "w")
if (output) then
output:write("// This file was automatically generated by buildinfo.lua\n#pragma once\n\n")
output:write("#define ETH_COMMIT_HASH "..hash.."\n")
output:write("#define ETH_CLEAN_REPO "..clean.."\n")
output:close()
end

25
windows/Ethereum.vcxproj

@ -160,6 +160,31 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="..\eth\main.cpp" /> <ClCompile Include="..\eth\main.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<CustomBuild Include="BuildInfo.lua">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Lua) "%(FullPath)" "$(IntDir)%(FileName).h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(FileName).h</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Lua) "%(FullPath)" "$(IntDir)%(FileName).h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(FileName).h</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Lua) "%(FullPath)" "$(IntDir)%(FileName).h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(FileName).h</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Lua) "%(FullPath)" "$(IntDir)%(FileName).h"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(FileName).h</Outputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../.git/index</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../.git/index</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../.git/index</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../.git/index</AdditionalInputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

16
windows/Ethereum.vcxproj.filters

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\eth\main.cpp" />
</ItemGroup>
<ItemGroup>
<Filter Include="Windows">
<UniqueIdentifier>{ed0eafbf-bbfb-4700-b7c0-9b58049cc681}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="BuildInfo.lua">
<Filter>Windows</Filter>
</CustomBuild>
</ItemGroup>
</Project>

6
windows/LibEthereum.props

@ -3,6 +3,7 @@
<ImportGroup Label="PropertySheets" /> <ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros"> <PropertyGroup Label="UserMacros">
<BoostDir>../../boost</BoostDir> <BoostDir>../../boost</BoostDir>
<Lua>"../../lua/lua"</Lua>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<OutDir>..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\</OutDir> <OutDir>..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\</OutDir>
@ -14,7 +15,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError> <TreatWarningAsError>true</TreatWarningAsError>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<AdditionalIncludeDirectories>include/$(ProjectName);../libethereum;$(BoostDir);../../leveldb/include;../../cryptopp;../secp256k1;../../miniupnp</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>include/$(ProjectName);$(IntDir);../libethereum;$(BoostDir);../../leveldb/include;../../cryptopp;../secp256k1;../../miniupnp</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ETH_BUILD_PLATFORM=Windows/VS2013;ETH_BUILD_TYPE=$(Configuration)-$(Platform);STATICLIB;LEVELDB_PLATFORM_WINDOWS;USE_NUM_BOOST;USE_FIELD_10X26;USE_FIELD_INV_BUILTIN;_WIN32_WINNT=0x0501;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>ETH_BUILD_PLATFORM=Windows/VS2013;ETH_BUILD_TYPE=$(Configuration)-$(Platform);STATICLIB;LEVELDB_PLATFORM_WINDOWS;USE_NUM_BOOST;USE_FIELD_10X26;USE_FIELD_INV_BUILTIN;_WIN32_WINNT=0x0501;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
@ -27,5 +28,8 @@
<BuildMacro Include="BoostDir"> <BuildMacro Include="BoostDir">
<Value>$(BoostDir)</Value> <Value>$(BoostDir)</Value>
</BuildMacro> </BuildMacro>
<BuildMacro Include="Lua">
<Value>$(Lua)</Value>
</BuildMacro>
</ItemGroup> </ItemGroup>
</Project> </Project>

6
windows/UseQt.props

@ -6,13 +6,12 @@
<QtBin>$(QtDir)/qtbase/bin</QtBin> <QtBin>$(QtDir)/qtbase/bin</QtBin>
<QtInclude>$(QtDir)/qtbase/include;../../Qt/Src/qtbase/include;../../Qt/Src/qtdeclarative/include</QtInclude> <QtInclude>$(QtDir)/qtbase/include;../../Qt/Src/qtbase/include;../../Qt/Src/qtdeclarative/include</QtInclude>
<QtLib>$(QtDir)/qtbase/lib;$(QtDir)/qtbase/plugins/platforms</QtLib> <QtLib>$(QtDir)/qtbase/lib;$(QtDir)/qtbase/plugins/platforms</QtLib>
<Lua>../../lua/lua</Lua>
</PropertyGroup> </PropertyGroup>
<PropertyGroup /> <PropertyGroup />
<ItemDefinitionGroup> <ItemDefinitionGroup>
<Link /> <Link />
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>..;$(IntDir);$(QtInclude);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..;$(QtInclude);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalLibraryDirectories>$(QtLib);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(QtLib);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -31,8 +30,5 @@
<BuildMacro Include="QtLib"> <BuildMacro Include="QtLib">
<Value>$(QtLib)</Value> <Value>$(QtLib)</Value>
</BuildMacro> </BuildMacro>
<BuildMacro Include="Lua">
<Value>$(Lua)</Value>
</BuildMacro>
</ItemGroup> </ItemGroup>
</Project> </Project>
Loading…
Cancel
Save