diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000000..efd07e11f5 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,17 @@ +This document describes breaking changes between Qtum releases for both RPC APIs and for blockchain consensus. + +# Sparknet (Testnet v1) + +Initial release + +# TBD (Testnet v2) + +## Consensus Parameters/Rules + +## EVM Behavior + +* Made block.coinbase use block.vtx[1].vout[1] for the coinbase address of PoS blocks +* Added check to coinbase to ensure that it is 0 if not a standard pubkeyhash address + +## RPC APIs + diff --git a/build-aux/m4/ax_boost_chrono.m4 b/build-aux/m4/ax_boost_chrono.m4 new file mode 100644 index 0000000000..4cd3b86041 --- /dev/null +++ b/build-aux/m4/ax_boost_chrono.m4 @@ -0,0 +1,118 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_CHRONO +# +# DESCRIPTION +# +# Test for Chrono library from the Boost C++ libraries. The macro requires +# a preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_CHRONO_LIB) +# +# And sets: +# +# HAVE_BOOST_CHRONO +# +# LICENSE +# +# Copyright (c) 2012 Xiyue Deng +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 5 + +AC_DEFUN([AX_BOOST_CHRONO], +[ + AC_ARG_WITH([boost-chrono], + AS_HELP_STRING([--with-boost-chrono@<:@=special-lib@:>@], + [use the Chrono library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-chrono=boost_chrono-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_chrono_lib="" + else + want_boost="yes" + ax_boost_user_chrono_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::Chrono library is available, + ax_cv_boost_chrono, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[boost::chrono::system_clock::time_point* time = new boost::chrono::system_clock::time_point; delete time;]])], + ax_cv_boost_chrono=yes, ax_cv_boost_chrono=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_chrono" = "xyes"; then + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_CHRONO,,[define if the Boost::Chrono library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + if test "x$ax_boost_user_chrono_lib" = "x"; then + for libextension in `ls $BOOSTLIBDIR/libboost_chrono*.so* $BOOSTLIBDIR/libboost_chrono*.dylib* $BOOSTLIBDIR/libboost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_chrono.*\)\.so.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + if test "x$link_chrono" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_chrono*.dll* $BOOSTLIBDIR/boost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_chrono.*\)\.dll.*$;\1;' -e 's;^\(boost_chrono.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_chrono_lib boost_chrono-$ax_boost_user_chrono_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the Boost::Chrono library!) + fi + if test "x$link_chrono" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_filesystem.m4 b/build-aux/m4/ax_boost_filesystem.m4 new file mode 100644 index 0000000000..12f7bc5e2e --- /dev/null +++ b/build-aux/m4/ax_boost_filesystem.m4 @@ -0,0 +1,118 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_boost_filesystem.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_FILESYSTEM +# +# DESCRIPTION +# +# Test for Filesystem library from the Boost C++ libraries. The macro +# requires a preceding call to AX_BOOST_BASE. Further documentation is +# available at . +# +# This macro calls: +# +# AC_SUBST(BOOST_FILESYSTEM_LIB) +# +# And sets: +# +# HAVE_BOOST_FILESYSTEM +# +# LICENSE +# +# Copyright (c) 2009 Thomas Porschberg +# Copyright (c) 2009 Michael Tindal +# Copyright (c) 2009 Roman Rybalko +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 28 + +AC_DEFUN([AX_BOOST_FILESYSTEM], +[ + AC_ARG_WITH([boost-filesystem], + AS_HELP_STRING([--with-boost-filesystem@<:@=special-lib@:>@], + [use the Filesystem library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-filesystem=boost_filesystem-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_filesystem_lib="" + else + want_boost="yes" + ax_boost_user_filesystem_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + LIBS_SAVED=$LIBS + LIBS="$LIBS $BOOST_SYSTEM_LIB" + export LIBS + + AC_CACHE_CHECK(whether the Boost::Filesystem library is available, + ax_cv_boost_filesystem, + [AC_LANG_PUSH([C++]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[using namespace boost::filesystem; + path my_path( "foo/bar/data.txt" ); + return 0;]])], + ax_cv_boost_filesystem=yes, ax_cv_boost_filesystem=no) + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_filesystem" = "xyes"; then + AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + if test "x$ax_boost_user_filesystem_lib" = "x"; then + for libextension in `ls -r $BOOSTLIBDIR/libboost_filesystem* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], + [link_filesystem="no"]) + done + if test "x$link_filesystem" != "xyes"; then + for libextension in `ls -r $BOOSTLIBDIR/boost_filesystem* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], + [link_filesystem="no"]) + done + fi + else + for ax_lib in $ax_boost_user_filesystem_lib boost_filesystem-$ax_boost_user_filesystem_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], + [link_filesystem="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the Boost::Filesystem library!) + fi + if test "x$link_filesystem" != "xyes"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + LIBS="$LIBS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_program_options.m4 b/build-aux/m4/ax_boost_program_options.m4 new file mode 100644 index 0000000000..2bdb593716 --- /dev/null +++ b/build-aux/m4/ax_boost_program_options.m4 @@ -0,0 +1,108 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_boost_program_options.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_BOOST_PROGRAM_OPTIONS +# +# DESCRIPTION +# +# Test for program options library from the Boost C++ libraries. The macro +# requires a preceding call to AX_BOOST_BASE. Further documentation is +# available at . +# +# This macro calls: +# +# AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) +# +# And sets: +# +# HAVE_BOOST_PROGRAM_OPTIONS +# +# LICENSE +# +# Copyright (c) 2009 Thomas Porschberg +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 24 + +AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], +[ + AC_ARG_WITH([boost-program-options], + AS_HELP_STRING([--with-boost-program-options@<:@=special-lib@:>@], + [use the program options library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-program-options=boost_program_options-gcc-mt-1_33_1 ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_program_options_lib="" + else + want_boost="yes" + ax_boost_user_program_options_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + export want_boost + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + AC_CACHE_CHECK([whether the Boost::Program_Options library is available], + ax_cv_boost_program_options, + [AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include + ]], + [[boost::program_options::error err("Error message"); + return 0;]])], + ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no) + AC_LANG_POP([C++]) + ]) + if test "$ax_cv_boost_program_options" = yes; then + AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + if test "x$ax_boost_user_program_options_lib" = "x"; then + for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], + [link_program_options="no"]) + done + if test "x$link_program_options" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_program_options*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], + [link_program_options="no"]) + done + fi + else + for ax_lib in $ax_boost_user_program_options_lib boost_program_options-$ax_boost_user_program_options_lib; do + AC_CHECK_LIB($ax_lib, main, + [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], + [link_program_options="no"]) + done + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the boost_program_options library!) + fi + if test "x$link_program_options" != "xyes"; then + AC_MSG_ERROR([Could not link against [$ax_lib] !]) + fi + fi + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_random.m4 b/build-aux/m4/ax_boost_random.m4 new file mode 100644 index 0000000000..f0b64ae20a --- /dev/null +++ b/build-aux/m4/ax_boost_random.m4 @@ -0,0 +1,122 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_boost_random.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_RANDOM +# +# DESCRIPTION +# +# Test for Random library from the Boost C++ libraries. The macro requires a +# preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_RANDOM_LIB) +# +# And sets: +# +# HAVE_BOOST_RANDOM +# +# LICENSE +# +# Copyright (c) 2008 Thomas Porschberg +# Copyright (c) 2008 Michael Tindal +# Copyright (c) 2013 Daniel Casimiro +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_BOOST_RANDOM], +[ + AC_ARG_WITH([boost-random], + AS_HELP_STRING([--with-boost-random@<:@=special-lib@:>@], + [use the Random library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-random=boost_random-gcc-mt ]), [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_random_lib="" + else + want_boost="yes" + ax_boost_user_random_lib="$withval" + fi + ], [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::Random library is available, + ax_cv_boost_random, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[@%:@include ]], + [[boost::random::random_device()();]])], + ax_cv_boost_random=yes, ax_cv_boost_random=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + + if test "x$ax_cv_boost_random" = "xyes"; then + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_RANDOM,,[define if the Boost::Random library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + if test "x$ax_boost_user_random_lib" = "x"; then + for libextension in `ls $BOOSTLIBDIR/libboost_random*.so* $BOOSTLIBDIR/libboost_random*.dylib* $BOOSTLIBDIR/libboost_random*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_random.*\)\.so.*$;\1;' -e 's;^lib\(boost_random.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_random.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_RANDOM_LIB="-l$ax_lib"; AC_SUBST(BOOST_RANDOM_LIB) link_random="yes"; break], + [link_random="no"]) + done + + if test "x$link_random" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_random*.dll* $BOOSTLIBDIR/boost_random*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_random.*\)\.dll.*$;\1;' -e 's;^\(boost_random.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_RANDOM_LIB="-l$ax_lib"; AC_SUBST(BOOST_RANDOM_LIB) link_random="yes"; break], + [link_random="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_random_lib boost_random-$ax_boost_user_random_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_RANDOM_LIB="-l$ax_lib"; AC_SUBST(BOOST_RANDOM_LIB) link_random="yes"; break], + [link_random="no"]) + done + fi + + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the library!) + fi + + if test "x$link_random" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_system.m4 b/build-aux/m4/ax_boost_system.m4 new file mode 100644 index 0000000000..323e2a676a --- /dev/null +++ b/build-aux/m4/ax_boost_system.m4 @@ -0,0 +1,121 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_boost_system.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_SYSTEM +# +# DESCRIPTION +# +# Test for System library from the Boost C++ libraries. The macro requires +# a preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_SYSTEM_LIB) +# +# And sets: +# +# HAVE_BOOST_SYSTEM +# +# LICENSE +# +# Copyright (c) 2008 Thomas Porschberg +# Copyright (c) 2008 Michael Tindal +# Copyright (c) 2008 Daniel Casimiro +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 20 + +AC_DEFUN([AX_BOOST_SYSTEM], +[ + AC_ARG_WITH([boost-system], + AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@], + [use the System library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-system=boost_system-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_system_lib="" + else + want_boost="yes" + ax_boost_user_system_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::System library is available, + ax_cv_boost_system, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + CXXFLAGS= + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[boost::system::error_category *a = 0;]])], + ax_cv_boost_system=yes, ax_cv_boost_system=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_system" = "xyes"; then + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + if test "x$ax_boost_user_system_lib" = "x"; then + for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], + [link_system="no"]) + done + if test "x$link_system" != "xyes"; then + for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], + [link_system="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], + [link_system="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the Boost::System library!) + fi + if test "x$link_system" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/build-aux/m4/ax_boost_thread.m4 b/build-aux/m4/ax_boost_thread.m4 new file mode 100644 index 0000000000..75e80e6e75 --- /dev/null +++ b/build-aux/m4/ax_boost_thread.m4 @@ -0,0 +1,187 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_boost_thread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_THREAD +# +# DESCRIPTION +# +# Test for Thread library from the Boost C++ libraries. The macro requires +# a preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_THREAD_LIB) +# +# And sets: +# +# HAVE_BOOST_THREAD +# +# LICENSE +# +# Copyright (c) 2009 Thomas Porschberg +# Copyright (c) 2009 Michael Tindal +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 33 + +AC_DEFUN([AX_BOOST_THREAD], +[ + AC_ARG_WITH([boost-thread], + AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@], + [use the Thread library from boost - + it is possible to specify a certain library for the linker + e.g. --with-boost-thread=boost_thread-gcc-mt ]), + [ + if test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_thread_lib="" + else + want_boost="yes" + ax_boost_user_thread_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::Thread library is available, + ax_cv_boost_thread, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + + case "x$host_os" in + xsolaris ) + CXXFLAGS="-pthreads $CXXFLAGS" + break; + ;; + xmingw32 ) + CXXFLAGS="-mthreads $CXXFLAGS" + break; + ;; + *android* ) + break; + ;; + * ) + CXXFLAGS="-pthread $CXXFLAGS" + break; + ;; + esac + + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM( + [[@%:@include ]], + [[boost::thread_group thrds; + return 0;]])], + ax_cv_boost_thread=yes, ax_cv_boost_thread=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_thread" = "xyes"; then + case "x$host_os" in + xsolaris ) + BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS" + break; + ;; + xmingw32 ) + BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS" + break; + ;; + *android* ) + break; + ;; + * ) + BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS" + break; + ;; + esac + + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_THREAD,, + [define if the Boost::Thread library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + case "x$host_os" in + *bsd* ) + LDFLAGS="-pthread $LDFLAGS" + break; + ;; + esac + if test "x$ax_boost_user_thread_lib" = "x"; then + for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [link_thread="yes"; break], + [link_thread="no"]) + done + if test "x$link_thread" != "xyes"; then + for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [link_thread="yes"; break], + [link_thread="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do + AC_CHECK_LIB($ax_lib, exit, + [link_thread="yes"; break], + [link_thread="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the Boost::Thread library!) + fi + if test "x$link_thread" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + else + BOOST_THREAD_LIB="-l$ax_lib" + case "x$host_os" in + *bsd* ) + BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS" + break; + ;; + xsolaris ) + BOOST_THREAD_LIB="$BOOST_THREAD_LIB -lpthread" + break; + ;; + xmingw32 ) + break; + ;; + *android* ) + break; + ;; + * ) + BOOST_THREAD_LIB="$BOOST_THREAD_LIB -lpthread" + break; + ;; + esac + AC_SUBST(BOOST_THREAD_LIB) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/contrib/builder-keys/qtum-neil-key.pgp b/contrib/builder-keys/qtum-neil-key.pgp new file mode 100644 index 0000000000..9aab8853a3 --- /dev/null +++ b/contrib/builder-keys/qtum-neil-key.pgp @@ -0,0 +1,96 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQINBFp2z5EBEACs3/KQy3naOrh5Z1UsQo2UQiEikydikGfHGmL65Q62B0ugNleu +RsaKemr4flzdwEvsQBqC3xtzR5Ruw4tAnBXRSkprGmh6Fm8Qt5/jfbP/KUJ5h+ws +2blq8J1vLnesNWpM38KxZ2SWQvA3a38ZNkNjiTN8FZp/ERxVSvAdaVIIopCkllL6 +zRq62tHkeROs1TpFRBcTEmgq7l0tsklB2oJXQSHS+2zEa3lLd7GqrsvCgSMz1VUK +NgHV4ovb2pYRs+2hRFwlOeE6xaFZ2nt5IzidgbEPJe9MlJx+O1VAZ257kutPhBZA +VnfWpQkci3xnKOBZSuOD/+KxTflbe0sxnt09KIZna6Bcmny7oxrWQVMyUD9wmAxF +67IxxOVHa6FHi6oeuIEwH5f3kIno4FOm3afoK9knLHYaGF2Kw2Z/GwolDQE9r9Ff +dBqZQDrHKjARJIpLjtZ5atPiOFvHP5QKT8w+H9cPNAVQJTIEVk83n/2lc+Fj3zIU +yL1uZYhruNCxUix7ehx/NRg6gjV4/5CMs/B4bE2xVEPsNCqmr2hYV3tKNRGKjw5e +SdosP5TBhxh4kxGJL0sR6/YeuNf96wvm16eDxZA7sxTGOHy+alkyWs33lcL3ppo3 +T/7Ju5neusPB4/y988lhT6eXX7j/33t+znHpzA3gr47rTld+Zb3ceJ7vywARAQAB +tAlxdHVtLW5laWyJAjgEEwECACIFAlp2z5ECGwMGCwkIBwMCBhUIAgkKCwQWAgMB +Ah4BAheAAAoJECWU8NCaiRpdiZYP+gLZojVHNwYYQfEMqblbCcbK2MEEUpHMPQBW +znMucKN4P2wFwqh9qF5nj+I+eBLmYV+ujf2/wVBk7ILIw1vKGMUa17vPEJYCQlH9 +i+z0UABv4Xsd4P4g5oI7R8IwKGJpoR8wxQTLXVWF1X9PdxBwI8dO0TEnONvBx9mT +l9vwTwSUOOIisaetHu7GroRjNII720XZR2AJIcrYpQjxzGK2+MO+aQ9byazKxv3p +RSpFFg2xmKIa25oIHpsqh6eLTJAdZI78tH5UBxn2cbr2mue3k5eKP/rszPtBmsvR +GAewpM53T1W6PYo34FT++vxe3HlLZHXdUZ1TlKpDXtYGMBP4QRPi2EXN6ip0YhEO +ChOFO6e34Y2W+uPHnD7fUqImkoq22CimOSPecV8hNuVPW8ngTnbg6cd7Ace3BHeQ +M/G/nqT1LwltdUhY3YfrVucovEWpNJJZ9Jm6dTtX0sb+YFAg3NrRa6kJWWpOMhjo +1zDDXxj2cdPzZc49xK/JLinucQNm8vrHf724ZDBFLhXgPR6O3zmtsja6E7NF8ZDb +y3jDRJNvqkWXrz3Gw2GNo/fz/1nCQ9E7LWBGiaD0URl/9+YNhuqWkL7sfRsFDAQY +sEFEj2B7wYKQ/TcUFyvRknrzAr2YwCjVw8SQrv/xIfWGu7rAlGe2IieL5L1sGAa6 +OOFT3nu+uQINBFp2z5EBEADDeJspw9IAivKX46EvT6JzaX12jPTIcqh9lRwR8k4n +UngZGUcBs0+qalapHjVEtiAWm+B8WsDF5zxcLcgmwkpU3H9hzRRIX7wgyGEEFM6S +p3/hGBz6UGR+bFSlevzupProwgvYD1sjn7RBw95uoCVMwLaWAWuTJnb3I3ty33WI +DcSSoKdYZYlwmVeAvBkF6umvLkdKA3+rxIP/5RzLYtExRo7NFXFpG6r1XrVbnRxp +C7J20Bz7MadWrBov83Zr5aNmJ4XTEu57VIXFmkhsxNW61pkD/IDJ9lDiTbswNq1h +dCcD0yetzMS56BO67Tgsdul51kqfa55ZuZH79QZ99M3Fn5j5izRAXNyVxsSPOfdI +3Lpf+kfNFTgb0brElPFwpu9sBUutHCkq3IJLUjQXyKJowcQjgrEmb6at62oZ5tVb +A2UlJoYfBIeOPwjf0Mt6QfDsw1N3HRjACl0mXKac4WDNXGvNzBqbjnKMyrOTL2/z +puzqQgskbdwbu1/cyi8GgLAPRF6bbefc3qcMj1TuT6WhK6fqmz6s9QhssYdJp6nA ++UEHDnFqkNsVzxS9NcHLQip4TreNlp/mh/N7WZ/DksFii7j3igxCttraR9cxpPOn +iI2F7iIaIeLqpVk6hDWnjxxEPsNMC0wldxVxGuF+YbpgLC/sfnODeQZosUKq2hbT +cwARAQABiQIfBBgBAgAJBQJads+RAhsMAAoJECWU8NCaiRpdO4QP/0LDJnTsVwU7 +Y/eeUCAnJNdPV5YZXC/CMqKWiteQj5HTjqpNggNAMOysCoZaZmsLCSnYIvhWkJFW +2BrxWvObGMKcnusxtC4R6nr0brdLFN++mjxqbOt6Ac5gJ8zaaRyCCTlrpekOKveX +cvv2ih4Z/G/Drqif5hbPLo/a5sDf54sGW4KMaFujzEvnN0mibcVVhVXatdwLnwmX +lN0vCdhwCQK8Q/4KHF6jtC5DGbOjYkflaGa/dDj0S5F+adY1TZKVWJY0HjI7icsN +3D+Ilm3UUU/WQbj/p5cQyNBHZjsU4iVcnByTiM6Obk3dWKOfD/Mn39CHwbCZjH61 +4hNFju47CxkK5yqVbCF7eUthcj9newTw2GDYJ5hzSyNwVTFomcmOyej66zQ3N0bO +UZMViFgorDh+fG4r/cE3Y8i/6Mz2eL9MN+mcsn8aqyS3gOeF0FZ1ircmeXtlGp1L +akSjX0MWFR/bADxIINmp385Oo+ugqEQ7g6qyQdWj40/fcuknydSW3sZd7y0HUOh4 +KfQxRbKZUtKVWIzBP5/Rq1nresNw2t/LZMuwSL/n0bq0iQrjVmYoGI6y4jasoSKJ +t375uwPmHZ7CQqQwQDqpzPamdnMyrnB+9UKSY6iWjOEnc4C4yk/ZlF3lrGvULMGi +J6dY6EVzPIChGX/TWfRTHTtDKbKcwtlbmQINBFp3JMwBEAC4JAzSyuYXnM1cYJEF +83IOuVmvQjvDEdWuOAqgcf1uwCpCnx+ganIpuICEwAzic7qXgjHcgTIr8iQtzWOd +2zFTNsC2lnmiTPLwpAuB4z9nfgVOGEqDoe8ksq26kmOaIPbl47/EeiX+CtbEU5/z +xIZKilK/b4mBf13AumUDcex99GNaFwrwZkwnHqsM1BOTKij/pOocSOA2rivqzEFE +vmrYiVWUVDktH12WLbw3Ay17uNK84MeCic0p+3eZnnlmdlGmTIhCv29mDdIW0FpZ +Opjn2I2AWd6961F6v1eocQUVlkjUsbh/40fcG525o4v6pZaPAB5mHLhKyY35WPyp +ppRr7yhW6XOaspLx7E0RmJ0cVklsjWWAcrNYb26IQ3R0UAolnHx+9RX7OFCXf8+t +TsnEAqZ2KqwhlNzGRlwMggCUhZ7B3oel1sM1uddZmbpY9abhcAaksaf/u8nskRSU +lWj6dP+b/2V2zidtsXfhxvAITJ7Gt3bMJETuvrQmt3zaSerPTjc3Zpi6ihI9B2Wa +QUaaS7/57q5GEUPpmhhqxBFgjg7b0wSstU6lT3VbQ9DTFGY/rExBTmpt7tyxA3n8 +lm+Xpo5cxJKBdUbwgINh8GD3YSr6/7RmfCYkd97P8fdaRmbD26Dhets2SYHs6xem +p02G+L6aHT79T2kePdQkRbfTTwARAQABtAlxdHVtLW5laWyJAjgEEwECACIFAlp3 +JMwCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEH4LWyrN9r3R66UP/AkU +PmPL7NsJ+WWonjXaHMPnvVVWhtGKs41zXm2WkJFeDMTgTJI10u7aYakeLs18GYol +G5awrsV4Qgmw4eNnS3Srs3LiDQd59tqYSUMUocS8BI7mSFsoZKjd9W3BPLMMmbYC +nQ4AdjoVbtJNO0ofZd9v22ckxJfJ658dW7IwhUeQbVQjbC1G7Rny7eBSg/eOVBg1 +0FUrm5l/tyWXG0XpLNbvV0zHVytLmultwVhS6e52QbPhTvH/T+JTZivCSuzx1oyN +ToCAb+uttAJT+HxBs2hA5UfsaZqGC7WrBycG+afv+0pnLaXHvkP2jt4XWQCddNlr +4BQrFlPginl+MmND9D0wD+xRdSmzkWP+y+z0733e1MPgep3HubK02QYP2bUa3KtA +mUZ5OTBWgEqGSfTJM7C1kAfMhkhDVnPG1Qw2pqNHeNCKgHyC6g6O1AXRCUbHNyQS +hrJQUoyiKTGw7Lh96KHuLQEkxiDO0pXamzWjxOrWSHkEq5FA9mGwBaHB/DpMMnEm +P5rOEUEH5r23Gsq8n+Ke8koepI0vWXupzQY8hmijx+QsfiwrN1j4aIm50Kvn/hps +BdAKbC7uB+xVpg0ZPKktqj+2Y2y6FOivyXYxfTypew3mgmYbhEbZ8Lq2aZt2E1TT +pd8uRgAhfEZKUTFGnh+gnMW7TVQxV6yT5qVLCJaKuQINBFp3JMwBEACxneVbjssC +A9rGBE/bvsMxot/HNRxhcdipmCYwrt0orTPL3pLnHOFH+J6LTarcG1pIQRHs1PV9 +yeRV436HcRrSCIznLKzInyWdpjtZFlewuQNx+bBEWwUY+d4mk1oYyPATJpXyAemf +9wHcpDNvUIc1smLK1JHIV3F5VTMGwhyfIbhhIugdcWmjJNsxB8IT6e/f3gl7R7Nt +PBtbeJlplC0sp7uAGed4eDGZo3fluHEvLeegnps7LtNqy9crokrZXccWEDrJXhD3 +VPSbh5u/Ua0p8zzKRH53upKXPJNtotkT0AiXcaF8wUiJU4z6sM0B0UBe28IsI8fE +ZHQdqtqQnaD79GH6nBQ8BTmwaCWbzPXv2K/OzylDNPv/yZTMl0bSgdfFc+GM5Kwp +qFhBO2urvOlIAbK0ACu8tdfDGzj6IZZzzhIqW194wMyucS0ZJB5PLmvrnl/TLNRN +8ukN9gWuHUSHwOWwkIf2gLjuBAQBWTXO+mTIvAXGFlUtMLp4sqOXMaziR99gb2Ar +/JFwxX11pudi4SJecRUXbyhjpzx3R2ifpCGQgZSlQGtnPiPLLA8KAfutzyZ4sSap +MN62qxDYbVuD55UyyQ3x/rTiicFi0/AX+0mUkxvcyk087H2C/iDHTBIind8I/BEs +1t4dk9d6EIALTfBGZixho/U0Vl2OR+DsjQARAQABiQIfBBgBAgAJBQJadyTMAhsM +AAoJEH4LWyrN9r3RDp8P/36fw+1rvRTuV3lYy8naYjyRl3zwLy+6LmxKk5cqktqq +G9su6VDBtYE0WigrzJT8oarY+bnuK+itVyccuwBtd8+bDixuxE7ufVQ+3+Rv5b4u +GRxyDKG1wHFtpnjqvhnvkSzbqvbMIGG9HeUHxv+DUpPsoOUfJc2MUGtvu7nK3oax +u1jOaZunb54IMAthh9V5aLkOnAR6Cu49F9flB53p7Xj+8e9fBInVCYOgZw+UMnr0 +zgpcPQm4bCy/RYaWlArBtVp+G8Nf/fogExwM8S/1XP4qXBS2kH/NAsMr6eWI1Pfd +gkWi68XEft+PVqIQL6XFLemGJ2q9aGXu+KmWyivb6euRrd8BEGnyeL8sm+8w7TPW +zb+dDDk0lrnl6yLd1gZw/ov/3Kkrj3EEbdNcaMHlPI0Yi5unWbb+brMeNi0GhR9e +UQ0ytR4X5pItvgdB6DnWbTF1NZI50eeZGQEe+9jLKKfNT6pCQKaa1h6Tyyv2qTCJ +geejS8Gq0V8hE5TULtLTJZ3SfIAxpz+KIbkrHCZPD8RMOW5NMvAA6l7a/wo+B5D2 +Ue4pdjSDN2eHDdbvwh3CuuuP6OMZwzxqFngSRiEmrjd4b97VLLg6eholsZlS3svA +lnJav/Dld+P1ieU9pJDxnMXQF8c6sXusBFuPpU/uedq4gTrtiDj1kbO3wTz8I+uA +=arln +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/guix/libexec/archive-all.sh b/contrib/guix/libexec/archive-all.sh new file mode 100755 index 0000000000..0b19fe8104 --- /dev/null +++ b/contrib/guix/libexec/archive-all.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env sh +pwd +if [ -z $1 ]; then + echo "You must specify a super-archive name." + exit 1 +fi + +if test -f "$1.tar"; then + rm "$1.tar" +fi +if test -f "$1.tar.gz"; then + rm "$1.tar.gz" +fi + +git archive --prefix "$1/" -o "$1.tar" HEAD +git submodule foreach --recursive "git archive --prefix=$1/\$displaypath/ --output=\$sha1.tar HEAD && tar --concatenate --file=$(pwd)/$1.tar \$sha1.tar && rm \$sha1.tar" + +gzip "$1.tar" + +if [ $# -gt 1 ]; then + if [ "$1.tar.gz" != "$2" ]; then + mv "$1.tar.gz" "$2" + fi +fi diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh new file mode 100755 index 0000000000..a976d1b660 --- /dev/null +++ b/contrib/install_db4.sh @@ -0,0 +1,260 @@ +#!/bin/sh +# Copyright (c) 2017-2021 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# Install libdb4.8 (Berkeley DB). + +export LC_ALL=C +set -e + +if [ -z "${1}" ]; then + echo "Usage: $0 [ ...]" + echo + echo "Must specify a single argument: the directory in which db4 will be built." + echo "This is probably \`pwd\` if you're at the root of the qtum repository." + exit 1 +fi + +expand_path() { + cd "${1}" && pwd -P +} + +BDB_PREFIX="$(expand_path "${1}")/db4"; shift; +BDB_VERSION='db-4.8.30.NC' +BDB_HASH='12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef' +BDB_URL="https://download.oracle.com/berkeley-db/${BDB_VERSION}.tar.gz" + +check_exists() { + command -v "$1" >/dev/null +} + +sha256_check() { + # Args: + # + if check_exists sha256sum; then + echo "${1} ${2}" | sha256sum -c + elif check_exists sha256; then + if [ "$(uname)" = "FreeBSD" ]; then + sha256 -c "${1}" "${2}" + else + echo "${1} ${2}" | sha256 -c + fi + else + echo "${1} ${2}" | shasum -a 256 -c + fi +} + +http_get() { + # Args: + # + # It's acceptable that we don't require SSL here because we manually verify + # content hashes below. + # + if [ -f "${2}" ]; then + echo "File ${2} already exists; not downloading again" + elif check_exists curl; then + curl --insecure --retry 5 "${1}" -o "${2}" + elif check_exists wget; then + wget --no-check-certificate "${1}" -O "${2}" + else + echo "Simple transfer utilities 'curl' and 'wget' not found. Please install one of them and try again." + exit 1 + fi + + sha256_check "${3}" "${2}" +} + +# Ensure the commands we use exist on the system +if ! check_exists patch; then + echo "Command-line tool 'patch' not found. Install patch and try again." + exit 1 +fi + +mkdir -p "${BDB_PREFIX}" +http_get "${BDB_URL}" "${BDB_VERSION}.tar.gz" "${BDB_HASH}" +tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX" +cd "${BDB_PREFIX}/${BDB_VERSION}/" + +# Apply a patch necessary when building with clang and c++11 (see https://community.oracle.com/thread/3952592) +patch --ignore-whitespace -p1 << 'EOF' +commit 3311d68f11d1697565401eee6efc85c34f022ea7 +Author: fanquake +Date: Mon Aug 17 20:03:56 2020 +0800 + + Fix C++11 compatibility + +diff --git a/dbinc/atomic.h b/dbinc/atomic.h +index 0034dcc..7c11d4a 100644 +--- a/dbinc/atomic.h ++++ b/dbinc/atomic.h +@@ -70,7 +70,7 @@ typedef struct { + * These have no memory barriers; the caller must include them when necessary. + */ + #define atomic_read(p) ((p)->value) +-#define atomic_init(p, val) ((p)->value = (val)) ++#define atomic_init_db(p, val) ((p)->value = (val)) + + #ifdef HAVE_ATOMIC_SUPPORT + +@@ -144,7 +144,7 @@ typedef LONG volatile *interlocked_val; + #define atomic_inc(env, p) __atomic_inc(p) + #define atomic_dec(env, p) __atomic_dec(p) + #define atomic_compare_exchange(env, p, o, n) \ +- __atomic_compare_exchange((p), (o), (n)) ++ __atomic_compare_exchange_db((p), (o), (n)) + static inline int __atomic_inc(db_atomic_t *p) + { + int temp; +@@ -176,7 +176,7 @@ static inline int __atomic_dec(db_atomic_t *p) + * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html + * which configure could be changed to use. + */ +-static inline int __atomic_compare_exchange( ++static inline int __atomic_compare_exchange_db( + db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval) + { + atomic_value_t was; +@@ -206,7 +206,7 @@ static inline int __atomic_compare_exchange( + #define atomic_dec(env, p) (--(p)->value) + #define atomic_compare_exchange(env, p, oldval, newval) \ + (DB_ASSERT(env, atomic_read(p) == (oldval)), \ +- atomic_init(p, (newval)), 1) ++ atomic_init_db(p, (newval)), 1) + #else + #define atomic_inc(env, p) __atomic_inc(env, p) + #define atomic_dec(env, p) __atomic_dec(env, p) +diff --git a/mp/mp_fget.c b/mp/mp_fget.c +index 5fdee5a..0b75f57 100644 +--- a/mp/mp_fget.c ++++ b/mp/mp_fget.c +@@ -617,7 +617,7 @@ alloc: /* Allocate a new buffer header and data space. */ + + /* Initialize enough so we can call __memp_bhfree. */ + alloc_bhp->flags = 0; +- atomic_init(&alloc_bhp->ref, 1); ++ atomic_init_db(&alloc_bhp->ref, 1); + #ifdef DIAGNOSTIC + if ((uintptr_t)alloc_bhp->buf & (sizeof(size_t) - 1)) { + __db_errx(env, +@@ -911,7 +911,7 @@ alloc: /* Allocate a new buffer header and data space. */ + MVCC_MPROTECT(bhp->buf, mfp->stat.st_pagesize, + PROT_READ); + +- atomic_init(&alloc_bhp->ref, 1); ++ atomic_init_db(&alloc_bhp->ref, 1); + MUTEX_LOCK(env, alloc_bhp->mtx_buf); + alloc_bhp->priority = bhp->priority; + alloc_bhp->pgno = bhp->pgno; +diff --git a/mp/mp_mvcc.c b/mp/mp_mvcc.c +index 34467d2..f05aa0c 100644 +--- a/mp/mp_mvcc.c ++++ b/mp/mp_mvcc.c +@@ -276,7 +276,7 @@ __memp_bh_freeze(dbmp, infop, hp, bhp, need_frozenp) + #else + memcpy(frozen_bhp, bhp, SSZA(BH, buf)); + #endif +- atomic_init(&frozen_bhp->ref, 0); ++ atomic_init_db(&frozen_bhp->ref, 0); + if (mutex != MUTEX_INVALID) + frozen_bhp->mtx_buf = mutex; + else if ((ret = __mutex_alloc(env, MTX_MPOOL_BH, +@@ -428,7 +428,7 @@ __memp_bh_thaw(dbmp, infop, hp, frozen_bhp, alloc_bhp) + #endif + alloc_bhp->mtx_buf = mutex; + MUTEX_LOCK(env, alloc_bhp->mtx_buf); +- atomic_init(&alloc_bhp->ref, 1); ++ atomic_init_db(&alloc_bhp->ref, 1); + F_CLR(alloc_bhp, BH_FROZEN); + } + +diff --git a/mp/mp_region.c b/mp/mp_region.c +index e6cece9..ddbe906 100644 +--- a/mp/mp_region.c ++++ b/mp/mp_region.c +@@ -224,7 +224,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg) + MTX_MPOOL_FILE_BUCKET, 0, &htab[i].mtx_hash)) != 0) + return (ret); + SH_TAILQ_INIT(&htab[i].hash_bucket); +- atomic_init(&htab[i].hash_page_dirty, 0); ++ atomic_init_db(&htab[i].hash_page_dirty, 0); + } + + /* +@@ -269,7 +269,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg) + hp->mtx_hash = (mtx_base == MUTEX_INVALID) ? MUTEX_INVALID : + mtx_base + i; + SH_TAILQ_INIT(&hp->hash_bucket); +- atomic_init(&hp->hash_page_dirty, 0); ++ atomic_init_db(&hp->hash_page_dirty, 0); + #ifdef HAVE_STATISTICS + hp->hash_io_wait = 0; + hp->hash_frozen = hp->hash_thawed = hp->hash_frozen_freed = 0; +diff --git a/mutex/mut_method.c b/mutex/mut_method.c +index 2588763..5c6d516 100644 +--- a/mutex/mut_method.c ++++ b/mutex/mut_method.c +@@ -426,7 +426,7 @@ atomic_compare_exchange(env, v, oldval, newval) + MUTEX_LOCK(env, mtx); + ret = atomic_read(v) == oldval; + if (ret) +- atomic_init(v, newval); ++ atomic_init_db(v, newval); + MUTEX_UNLOCK(env, mtx); + + return (ret); +diff --git a/mutex/mut_tas.c b/mutex/mut_tas.c +index f3922e0..e40fcdf 100644 +--- a/mutex/mut_tas.c ++++ b/mutex/mut_tas.c +@@ -46,7 +46,7 @@ __db_tas_mutex_init(env, mutex, flags) + + #ifdef HAVE_SHARED_LATCHES + if (F_ISSET(mutexp, DB_MUTEX_SHARED)) +- atomic_init(&mutexp->sharecount, 0); ++ atomic_init_db(&mutexp->sharecount, 0); + else + #endif + if (MUTEX_INIT(&mutexp->tas)) { +@@ -486,7 +486,7 @@ __db_tas_mutex_unlock(env, mutex) + F_CLR(mutexp, DB_MUTEX_LOCKED); + /* Flush flag update before zeroing count */ + MEMBAR_EXIT(); +- atomic_init(&mutexp->sharecount, 0); ++ atomic_init_db(&mutexp->sharecount, 0); + } else { + DB_ASSERT(env, sharecount > 0); + MEMBAR_EXIT(); +EOF + +# The packaged config.guess and config.sub are ancient (2009) and can cause build issues. +# Replace them with modern versions. +# See https://github.com/bitcoin/bitcoin/issues/16064 +CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f' +CONFIG_GUESS_HASH='c8f530e01840719871748a8071113435bdfdf75b74c57e78e47898edea8754ae' +CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f' +CONFIG_SUB_HASH='3969f7d5f6967ccc6f792401b8ef3916a1d1b1d0f0de5a4e354c95addb8b800e' + +rm -f "dist/config.guess" +rm -f "dist/config.sub" + +http_get "${CONFIG_GUESS_URL}" dist/config.guess "${CONFIG_GUESS_HASH}" +http_get "${CONFIG_SUB_URL}" dist/config.sub "${CONFIG_SUB_HASH}" + +cd build_unix/ + +"${BDB_PREFIX}/${BDB_VERSION}/dist/configure" \ + --enable-cxx --disable-shared --disable-replication --with-pic --prefix="${BDB_PREFIX}" \ + "${@}" + +make install + +echo +echo "db4 build complete." +echo +# shellcheck disable=SC2016 +echo 'When compiling qtumd, run `./configure` in the following way:' +echo +echo " export BDB_PREFIX='${BDB_PREFIX}'" +# shellcheck disable=SC2016 +echo ' ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" ...' diff --git a/contrib/script/build-qtum-linux.sh b/contrib/script/build-qtum-linux.sh new file mode 100755 index 0000000000..0a1db5e016 --- /dev/null +++ b/contrib/script/build-qtum-linux.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +# Build Qtum package on Linux OS, for example: qtum-22.1-x86_64-pc-linux-gnu.tar.gz + +BUILD_PARAM=$1 + +if RECENT_TAG="$(git describe --exact-match HEAD 2> /dev/null)"; then + VERSION="${RECENT_TAG#v}" +else + VERSION="$(git rev-parse --short=12 HEAD)" +fi +DISTNAME="qtum-${VERSION}" + +SRC_DIR=$PWD +cd ../../ +./autogen.sh +cd ./depends +make clean +make $BUILD_PARAM +HOST="$(./config.guess 2> /dev/null)" +if [[ ! -d "./$HOST" ]] +then + echo "HOST platform not built." + exit 1 +fi +cd .. +which yum &> /dev/null && SECCMP="--without-seccomp" +CONFIG_SITE=$PWD/depends/$HOST/share/config.site ./configure --disable-ccache --disable-maintainer-mode --disable-dependency-tracking --enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests --disable-fuzz-binary $SECCMP CFLAGS="-O2" CXXFLAGS="-O2" LDFLAGS="-static-libstdc++ -Wl,-O2" +make clean +make $BUILD_PARAM +INSTALLPATH="${PWD}/installed/${HOST}" +rm -r ${INSTALLPATH} +make install DESTDIR=${INSTALLPATH} +mv ${INSTALLPATH}/usr/local ${INSTALLPATH}/usr/${DISTNAME} +DISTPATH=${INSTALLPATH}/usr +cp ./README.md ${DISTPATH}/${DISTNAME} +cd ${DISTPATH} +find . -name "lib*.la" -delete +find . -name "lib*.a" -delete +rm -rf ./${DISTNAME}/lib/pkgconfig +cd ${DISTPATH}/${DISTNAME}/bin +strip * +cd ${DISTPATH}/${DISTNAME}/lib +strip * +cd ${DISTPATH} +find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${SRC_DIR}/${DISTNAME}-${HOST}.tar.gz +cd ${SRC_DIR} +sha256sum ${DISTNAME}-${HOST}.tar.gz > ${DISTNAME}-${HOST}.hash diff --git a/contrib/script/setup-centos7.sh b/contrib/script/setup-centos7.sh new file mode 100755 index 0000000000..ceb713ffe2 --- /dev/null +++ b/contrib/script/setup-centos7.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# Setup Qtum build environment for CentOS 7 +yum -y install centos-release-scl +yum -y install devtoolset-10-gcc devtoolset-10-gcc-c++ +yum -y install autoconf automake binutils bison ca-certificates curl faketime git libtool patch pkgconfig python3 python3-pip cmake curl-devel gmp-devel libmicrohttpd-devel miniupnpc-devel +yum -y install http://repo.okay.com.mx/centos/7/x86_64/release/automake-1.14-1.el7.x86_64.rpm + +DEVTOOLSET="source scl_source enable devtoolset-10" +FILENAME="/etc/profile" +if grep "$DEVTOOLSET" $FILENAME > /dev/null +then + echo "devtoolset-10 enabled" +else + echo $DEVTOOLSET | tee -a $FILENAME + reboot +fi diff --git a/contrib/script/setup-ubuntu16.sh b/contrib/script/setup-ubuntu16.sh new file mode 100755 index 0000000000..c0249436d3 --- /dev/null +++ b/contrib/script/setup-ubuntu16.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +# Setup Qtum build environment for Ubuntu 16 + +sudo add-apt-repository ppa:ubuntu-toolchain-r/test +sudo apt-get update +sudo apt-get install autoconf automake binutils bison bsdmainutils ca-certificates curl faketime g++-9 gcc-9 git libtool patch pkg-config python3 python3-pip cmake libcurl4-openssl-dev libgmp-dev libmicrohttpd-dev libminiupnpc-dev -y +sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90 --slave /usr/bin/g++ g++ /usr/bin/g++-9 --slave /usr/bin/gcov gcov /usr/bin/gcov-9 diff --git a/contrib/sync/headersync_params.py b/contrib/sync/headersync_params.py new file mode 100755 index 0000000000..029a6508d7 --- /dev/null +++ b/contrib/sync/headersync_params.py @@ -0,0 +1,343 @@ +"""Script to find the optimal parameters for the headerssync module through simulation.""" + +from math import log, exp, sqrt +from datetime import datetime, timedelta +import random + +### Parameters + +# Aim for still working fine at some point in the future. [datetime] +TIME = datetime(2025, 10, 18) + +# Expected block interval. [timedelta] +BLOCK_INTERVAL = timedelta(seconds=32) + +# The number of headers corresponding to the minchainwork parameter. [headers] +MINCHAINWORK_HEADERS = 2636000 + +# Combined processing bandwidth from all attackers to one victim. [bit/s] +# 6 Gbit/s is approximately the speed at which a single thread of a Ryzen 5950X CPU thread can hash +# headers. In practice, the victim's network bandwidth and network processing overheads probably +# impose a far lower number, but it's a useful upper bound. +ATTACK_BANDWIDTH = 6000000000 + +# How much additional permanent memory usage are attackers (jointly) allowed to cause in the victim, +# expressed as fraction of the normal memory usage due to mainchain growth, for the duration the +# attack is sustained. [unitless] +# 0.2 means that attackers, while they keep up the attack, can cause permanent memory usage due to +# headers storage to grow at 1.2 header per BLOCK_INTERVAL. +ATTACK_FRACTION = 0.2 + +# When this is set, the mapping from interval size to memory usage (at optimal buffer size for that +# interval) is assumed to be convex. This greatly speeds up the computation, and does not appear +# to influence the outcome. Set to False for a stronger guarantee to get the optimal result. +ASSUME_CONVEX = True + +### Explanation +# +# The headerssync module implements a DoS protection against low-difficulty header spam which does +# not rely on checkpoints. In short it works as follows: +# +# - (initial) header synchronization is split into two phases: +# - A commitment phase, in which headers are downloaded from the peer, and a very compact +# commitment to them is remembered in per-peer memory. The commitment phase ends when the +# received chain's combined work reaches a predetermined threshold. +# - A redownload phase, during which the headers are downloaded a second time from the same peer, +# and compared against the commitment constructed in the first phase. If there is a match, the +# redownloaded headers are fed to validation and accepted into permanent storage. +# +# This separation guarantees that no headers are accepted into permanent storage without +# requiring the peer to first prove the chain actually has sufficient work. +# +# - To actually implement this commitment mechanism, the following approach is used: +# - Keep a *1 bit* commitment (constructed using a salted hash function), for every block whose +# height is a multiple of {interval} plus an offset value. If RANDOMIZE_OFFSET, the offset, +# like the salt, is chosen randomly when the synchronization starts and kept fixed afterwards. +# - When redownloading, headers are fed through a per-peer queue that holds {bufsize} headers, +# before passing them to validation. All the headers in this queue are verified against the +# commitment bits created in the first phase before any header is released from it. This means +# {bufsize/interval} bits are checked "on top of" each header before actually processing it, +# which results in a commitment structure with roughly {bufsize/interval} bits of security, as +# once a header is modified, due to the prevhash inclusion, all future headers necessarily +# change as well. +# +# The question is what these $interval and parameters need to be set to. This program +# exhaustively tests a range of values to find the optimal choice, taking into account: +# +# - Minimizing the (maximum of) two scenarios that trigger per-peer memory usage: +# +# - When downloading a (likely honest) chain that reaches the chainwork threshold after {n} +# blocks, and then redownloads them, we will consume per-peer memory that is sufficient to +# store {n/interval} commitment bits and {bufsize} headers. We only consider attackers without +# sufficient hashpower (as otherwise they are from a PoW perspective not attackers), which +# means {n} is restricted to the honest chain's length before reaching minchainwork. +# +# - When downloading a (likely false) chain of {n} headers that never reaches the chainwork +# threshold, we will consume per-peer memory that is sufficient to store {n/interval} +# commitment bits. Such a chain may be very long, by exploiting the timewarp bug to avoid +# ramping up difficulty. There is however an absolute limit on how long such a chain can be: 6 +# blocks per second since genesis, due to the increasing MTP consensus rule. +# +# - Not gratuitously preventing synchronizing any valid chain, however difficult such a chain may +# be to construct. In particular, the above scenario with an enormous timewarp-expoiting chain +# cannot simply be ignored, as it is legal that the honest main chain is like that. We however +# do not bother minimizing the memory usage in that case (because a billion-header long honest +# chain will inevitably use far larger amounts of memory than designed for). +# +# - Keep the rate at which attackers can get low-difficulty headers accepted to the block index +# negligible. Specifically, the possibility exists for an attacker to send the honest main +# chain's headers during the commitment phase, but then start deviating at an attacker-chosen +# point by sending novel low-difficulty headers instead. Depending on how high we set the +# {bufsize/interval} ratio, we can make the probability that such a header makes it in +# arbitrarily small, but at the cost of higher memory during the redownload phase. It turns out, +# some rate of memory usage growth is expected anyway due to chain growth, so permitting the +# attacker to increase that rate by a small factor isn't concerning. The attacker may start +# somewhat later than genesis, as long as the difficulty doesn't get too high. This reduces +# the attacker bandwidth required at the cost of higher PoW needed for constructing the +# alternate chain. This trade-off is ignored here, as it results in at most a small constant +# factor in attack rate. + + +### System properties + +# Headers in the redownload buffer are stored without prevhash. [bits] +COMPACT_HEADER_SIZE = 176 * 8 + +# How many bits a header uses in P2P protocol. [bits] +NET_HEADER_SIZE = 246 * 8 + +# How many headers are sent at once. [headers] +HEADER_BATCH_COUNT = 2000 + +# Whether or not the offset of which blocks heights get checksummed is randomized. +RANDOMIZE_OFFSET = True + + +### Derived values + +# The maximum number of headers a valid Bitcoin chain can have at time TIME. [headers] +# When exploiting the timewarp attack, this can be 1 header per 4 seconds since genesis. +MAX_HEADERS = 5000 + ((TIME + timedelta(hours=2) - datetime(2017, 9, 6)) // timedelta(seconds=4)) + +# What rate of headers worth of RAM attackers are allowed to cause in the victim. [headers/s] +LIMIT_HEADERRATE = ATTACK_FRACTION / BLOCK_INTERVAL.total_seconds() + +# How many headers can attackers (jointly) send a victim per second. [headers/s] +NET_HEADERRATE = ATTACK_BANDWIDTH / NET_HEADER_SIZE + +# What fraction of headers sent by attackers can at most be accepted by a victim [unitless] +LIMIT_FRACTION = LIMIT_HEADERRATE / NET_HEADERRATE + +# How many headers we permit attackers to cause being accepted per attack. [headers/attack] +ATTACK_HEADERS = LIMIT_FRACTION * MINCHAINWORK_HEADERS + +# When interval*bufsize = MEMORY_SCALE, the per-peer memory for a mainchain sync and a maximally +# long low-difficulty header sync are equal. [headers/bit] +MEMORY_SCALE = (MAX_HEADERS - MINCHAINWORK_HEADERS) / COMPACT_HEADER_SIZE + + +def lambert_w(value): + """Solve the equation x*exp(x)=value (x > 0, value > 0).""" + # Initial approximation. + approx = max(log(value), 0.0) + for _ in range(10): + # Newton-Rhapson iteration steps. + approx += (value * exp(-approx) - approx) / (approx + 1.0) + return approx + + +def attack_rate(interval, bufsize, limit=None): + """Compute maximal accepted headers per attack in (interval, bufsize) configuration. + + If limit is provided, the computation is stopped early when the result is known to exceed the + value in limit. + """ + + max_rate = None + max_honest = None + # Let the current batch 0 being received be the first one in which the attacker starts lying. + # They will only ever start doing so right after a commitment block, but where that is can be + # in a number of places. Let honest be the number of honest headers in this current batch, + # preceding the forged ones. + for honest in range(HEADER_BATCH_COUNT): + # The number of headers the attack under consideration will on average get accepted. + # This is the number being computed. + rate = 0 + + # Iterate over the possible alignments of commitments w.r.t. the first batch. In case + # the alignments are randomized, try all values. If not, the attacker can know/choose + # the alignemnt, and will always start forging right after a commitment. + if RANDOMIZE_OFFSET: + align_choices = list(range(interval)) + else: + align_choices = [(honest - 1) % interval] + # Now loop over those possible alignment values, computing the average attack rate + # over them by dividing each contribution by len(align_choices). + for align in align_choices: + # These state variables capture the situation after receiving the first batch. + # - The number of headers received after the last commitment for an honest block: + after_good_commit = HEADER_BATCH_COUNT - honest + ((honest - align - 1) % interval) + # - The number of forged headers in the redownload buffer: + forged_in_buf = HEADER_BATCH_COUNT - honest + + # Now iterate over the next batches of headers received, adding contributions to the + # rate variable. + while True: + # Process the first HEADER_BATCH_COUNT headers in the buffer: + accept_forged_headers = max(forged_in_buf - bufsize, 0) + forged_in_buf -= accept_forged_headers + if accept_forged_headers: + # The probability the attack has not been detected yet at this point: + prob = 0.5 ** (after_good_commit // interval) + # Update attack rate, divided by align_choices to average over the alignments. + old_rate = rate + rate += accept_forged_headers * prob / len(align_choices) + # If this means we exceed limit, bail out early (performance optimization). + if limit is not None and rate >= limit: + return rate, None + # If the maximal term being added is negligible compared to rate, stop + # iterating. + if HEADER_BATCH_COUNT * prob < 1.0e-16 * rate * len(align_choices): + break + # Update state from a new incoming batch (which is all forged) + after_good_commit += HEADER_BATCH_COUNT + forged_in_buf += HEADER_BATCH_COUNT + + if max_rate is None or rate > max_rate: + max_rate = rate + max_honest = honest + + return max_rate, max_honest + + +def memory_usage(interval, bufsize): + """How much memory (max,mainchain,timewarp) does the (interval,bufsize) configuration need?""" + + # Per-peer memory usage for a timewarp chain that never meets minchainwork + mem_timewarp = MAX_HEADERS // interval + # Per-peer memory usage for being fed the main chain + mem_mainchain = (MINCHAINWORK_HEADERS // interval) + bufsize * COMPACT_HEADER_SIZE + # Maximum per-peer memory usage + max_mem = max(mem_timewarp, mem_mainchain) + + return max_mem, mem_mainchain, mem_timewarp + +def find_bufsize(interval, attack_headers, max_mem=None, min_bufsize=1): + """Determine how big bufsize needs to be given a specific interval length. + + Given an interval, find the smallest value of bufsize such that the attack rate against the + (interval, bufsize) configuration is below attack_headers. If max_mem is provided, and no + such bufsize exists that needs less than max_mem bits of memory, None is returned. + min_bufsize is the minimal result to be considered.""" + + if max_mem is None: + succ_buf = min_bufsize - 1 + fail_buf = min_bufsize + # First double iteratively until an upper bound for failure is found. + while True: + if attack_rate(interval, fail_buf, attack_headers)[0] < attack_headers: + break + succ_buf, fail_buf = fail_buf, 3 * fail_buf - 2 * succ_buf + else: + # If a long low-work header chain exists that exceeds max_mem already, give up. + if MAX_HEADERS // interval > max_mem: + return None + # Otherwise, verify that the maximal buffer size that permits a mainchain sync with less + # than max_mem memory is sufficient to get the attack rate below attack_headers. If not, + # also give up. + max_buf = (max_mem - (MINCHAINWORK_HEADERS // interval)) // COMPACT_HEADER_SIZE + if max_buf < min_bufsize: + return None + if attack_rate(interval, max_buf, attack_headers)[0] >= attack_headers: + return None + # If it is sufficient, that's an upper bound to start our search. + succ_buf = min_bufsize - 1 + fail_buf = max_buf + + # Then perform a bisection search to narrow it down. + while fail_buf > succ_buf + 1: + try_buf = (succ_buf + fail_buf) // 2 + if attack_rate(interval, try_buf, attack_headers)[0] >= attack_headers: + succ_buf = try_buf + else: + fail_buf = try_buf + return fail_buf + + +def optimize(): + """Find the best (interval, bufsize) configuration and print it out.""" + + # Compute approximation for {bufsize/interval}, using a formula for a simplified problem. + approx_ratio = lambert_w(log(4) * MEMORY_SCALE / ATTACK_HEADERS**2) / log(4) + # Use those for a first attempt. + print("Searching configurations:") + interval = int(sqrt(MEMORY_SCALE / approx_ratio) + 0.5) + bufsize = find_bufsize(interval, ATTACK_HEADERS) + mem = memory_usage(interval, bufsize) + best = (interval, bufsize, mem) + maps = [(interval, bufsize), (MINCHAINWORK_HEADERS + 1, None)] + print(f"- Initial: interval={interval}, buffer={bufsize}, mem={mem[0] / 8192:.3f} KiB") + + # Consider all interval values between 1 and MINCHAINWORK_HEADERS, except the one just tried. + intervals = [iv for iv in range(1, MINCHAINWORK_HEADERS + 1) if iv != interval] + # Iterate, picking a random element from intervals, computing its corresponding bufsize, and + # then using the result to shrink the interval. + while True: + # Remove all intervals whose memory usage for low-work long chain sync exceed the best + # memory usage we've found so far. + intervals = [interval for interval in intervals if MAX_HEADERS // interval < best[2][0]] + # Stop if there is nothing left to try. + if len(intervals) == 0: + break + # Pick a random remaining option for interval size, and compute corresponding bufsize. + interval = intervals.pop(random.randrange(len(intervals))) + # The buffer size (at a given attack level) cannot shrink as the interval grows. Find the + # largest interval smaller than the selected one we know the buffer size for, and use that + # as a lower bound to find_bufsize. + min_bufsize = max([(i, b) for i, b in maps if i < interval] + [(1,0)])[1] + bufsize = find_bufsize(interval, ATTACK_HEADERS, best[2][0], min_bufsize) + if bufsize is not None: + # We found an (interval, bufsize) configuration with better memory usage than our best + # so far. Remember it for future lower bounds. + maps.append((interval, bufsize)) + mem = memory_usage(interval, bufsize) + assert mem[0] <= best[2][0] + if ASSUME_CONVEX: + # Remove all intervals that are on the other side of the former best as the new + # best. + intervals = [h for h in intervals if (h < best[0]) == (interval < best[0])] + best = (interval, bufsize, mem) + print(f"- New best: interval={interval}, buffer={bufsize}, mem={mem[0] / 8192:.3f} KiB") + else: + # The (interval, bufsize) configuration we found is worse than what we already had. + if ASSUME_CONVEX: + # Remove all intervals that are on the other side of the tried configuration as the + # best one. + intervals = [h for h in intervals if (h < interval) == (best[0] < interval)] + + # Compute accurate statistics for the best found configuration. + interval, bufsize, mem = best + _, mem_mainchain, mem_timewarp = mem + headers_per_attack, attack_honest = attack_rate(interval, bufsize) + attack_volume = NET_HEADER_SIZE * MINCHAINWORK_HEADERS + # And report them. + print() + print("Optimal configuration:") + print() + print("//! Store one header commitment per HEADER_COMMITMENT_INTERVAL blocks.") + print(f"constexpr size_t HEADER_COMMITMENT_INTERVAL{{{interval}}};") + print() + print("//! Only feed headers to validation once this many headers on top have been") + print("//! received and validated against commitments.") + print(f"constexpr size_t REDOWNLOAD_BUFFER_SIZE{{{bufsize}}};" + f" // {bufsize} / {interval} = ~{bufsize/interval:.1f} commitments") + print() + print("Properties:") + print(f"- Per-peer memory for mainchain sync: {mem_mainchain / 8192:.3f} KiB") + print(f"- Per-peer memory for timewarp attack: {mem_timewarp / 8192:.3f} KiB") + print(f"- Attack rate: memory growth of {headers_per_attack:.5g} headers/attack") + print(f" (where each attack costs {attack_volume / 8388608:.3f} MiB bandwidth)") + print(f"- Best attack starts forging at position {attack_honest} in batch") + + +optimize() diff --git a/depends/packages/gmp.mk b/depends/packages/gmp.mk new file mode 100644 index 0000000000..ecf85ec994 --- /dev/null +++ b/depends/packages/gmp.mk @@ -0,0 +1,33 @@ +package=gmp +$(package)_version=6.2.1 +$(package)_sha256_hash=fd4829912cddd12f84181c3451cc752be224643e87fac497b69edddadc49b4f2 +$(package)_file_name=$(package)-$($(package)_version).tar.xz +$(package)_download_path=https://gmplib.org/download/$(package) + +define $(package)_set_vars + $(package)_config_opts=--prefix=$(host_prefix) + $(package)_config_opts += --disable-shared --enable-static --enable-cxx + $(package)_config_opts += --enable-option-checking + $(package)_config_opts_linux=--with-pic + $(package)_config_opts_darwin += --with-pic +endef + +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + sed -i "s|libstdc++.la|libstdc++.a|" lib/libgmpxx.la +endef diff --git a/depends/packages/native_b2.mk b/depends/packages/native_b2.mk new file mode 100644 index 0000000000..aaa37cdcfa --- /dev/null +++ b/depends/packages/native_b2.mk @@ -0,0 +1,20 @@ +package=native_b2 +$(package)_version=$(boost_version) +$(package)_download_path=$(boost_download_path) +$(package)_file_name=$(boost_file_name) +$(package)_sha256_hash=$(boost_sha256_hash) +$(package)_build_subdir=tools/build/src/engine +ifneq (,$(findstring clang,$($(package)_cxx))) +$(package)_toolset_$(host_os)=clang +else +$(package)_toolset_$(host_os)=gcc +endif + +define $(package)_build_cmds + CXX="$($(package)_cxx)" CXXFLAGS="$($(package)_cxxflags)" ./build.sh "$($(package)_toolset_$(host_os))" +endef + +define $(package)_stage_cmds + mkdir -p "$($(package)_staging_prefix_dir)"/bin/ && \ + cp b2 "$($(package)_staging_prefix_dir)"/bin/ +endef diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk new file mode 100644 index 0000000000..dde6085cc5 --- /dev/null +++ b/depends/packages/openssl.mk @@ -0,0 +1,75 @@ +package=openssl +$(package)_version=1.1.1k +$(package)_download_path=https://www.openssl.org/source +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5 + +define $(package)_set_vars +$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" +$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl +$(package)_config_opts+=no-camellia +$(package)_config_opts+=no-capieng +$(package)_config_opts+=no-cast +$(package)_config_opts+=no-comp +$(package)_config_opts+=no-dso +$(package)_config_opts+=no-dtls1 +$(package)_config_opts+=no-ec_nistp_64_gcc_128 +$(package)_config_opts+=no-gost +$(package)_config_opts+=no-heartbeats +$(package)_config_opts+=no-idea +$(package)_config_opts+=no-md2 +$(package)_config_opts+=no-mdc2 +$(package)_config_opts+=no-rc4 +$(package)_config_opts+=no-rc5 +$(package)_config_opts+=no-rdrand +$(package)_config_opts+=no-rfc3779 +$(package)_config_opts+=no-sctp +$(package)_config_opts+=no-seed +$(package)_config_opts+=no-shared +$(package)_config_opts+=no-ssl-trace +$(package)_config_opts+=no-ssl2 +$(package)_config_opts+=no-ssl3 +$(package)_config_opts+=no-unit-test +$(package)_config_opts+=no-weak-ssl-ciphers +$(package)_config_opts+=no-whirlpool +$(package)_config_opts+=no-zlib +$(package)_config_opts+=no-zlib-dynamic +$(package)_config_opts+=-pipe -O2 $($(package)_cppflags) +$(package)_config_opts_linux=-fPIC -Wa,--noexecstack +$(package)_config_opts_x86_64_linux=linux-x86_64 +$(package)_config_opts_i686_linux=linux-generic32 +$(package)_config_opts_arm_linux=linux-generic32 +$(package)_config_opts_armv7l_linux=linux-generic32 +$(package)_config_opts_aarch64_linux=linux-generic64 +$(package)_config_opts_mipsel_linux=linux-generic32 +$(package)_config_opts_mips_linux=linux-generic32 +$(package)_config_opts_powerpc64_linux=linux-generic64 +$(package)_config_opts_powerpc64le_linux=linux-generic64 +$(package)_config_opts_riscv32_linux=linux-generic32 +$(package)_config_opts_riscv64_linux=linux-generic64 +$(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc +$(package)_config_opts_aarch64_darwin += darwin64-arm64-cc +$(package)_config_opts_x86_64_mingw32=mingw64 +$(package)_config_opts_i686_mingw32=mingw +endef + +define $(package)_preprocess_cmds + sed -i.old "s/built on: \$date/built on: date not available/g" util/mkbuildinf.pl && \ + sed -i.old "s|\"engines\", \"apps\", \"test\"|\"engines\"|" Configure +endef + +define $(package)_config_cmds + ./Configure $($(package)_config_opts) +endef + +define $(package)_build_cmds + $(MAKE) -j1 build_libs libcrypto.pc libssl.pc openssl.pc +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -j1 install_sw +endef + +define $(package)_postprocess_cmds + rm -rf share bin etc +endef diff --git a/doc/hardware-wallet.md b/doc/hardware-wallet.md new file mode 100644 index 0000000000..a3d0fbc26a --- /dev/null +++ b/doc/hardware-wallet.md @@ -0,0 +1,39 @@ +HARDWARE WALLET +==================== + +## Tools for hardware device support + +Use [Ledger Nano S Loader](https://github.com/qtumproject/qtum-ledger-loader/releases) to install the Ledger Nano S Wallet and Ledger Nano S Stake application. + +Use [HWI](https://github.com/qtumproject/HWI) for command line interaction with the Hardware Wallet. + +## Graphical interface for hardware device + +`qtum-qt` provides an interface for interacting with hardware wallet devices. + +Set the HWI tool path using the menu `Settings -> Option -> Main -> HWI Tool Path` and restart `qtum-qt`, the tool is needed for hardware wallet interaction. + +Use the menu `File -> Create Wallet... -> Use a hardware device` for creating hardware wallet. The hardware wallet needs to be connected and the wallet application started. + +Use hardware wallets to send/receive coins. + +Ledger Nano S has support for smart contracts using the wallet application that can be installed with [Ledger Nano S Loader](https://github.com/qtumproject/qtum-ledger-loader/releases), it also supports delegation to a staker for offline staking. + +## Graphical interface for hardware device staking + +Ledger Nano S has support for staking using the staking application that can be installed with [Ledger Nano S Loader](https://github.com/qtumproject/qtum-ledger-loader/releases). + +Using the menu `Settings -> Option -> Main -> Select Ledger device for staking` to select ledger for staking that the `qtum-qt` will automatically connect when started. + +The staking will be active until the application is closed and will be automatically started when `qtum-qt` is started and the staking wallet is loaded. + +## Command line interface for hardware device staking + +`qtumd -hwitoolpath= -stakerledgerid= -wallet ` + +`` is the location where the HWI is installed. In GUI, the value in menu `Settings -> Option -> Main -> HWI Tool Path`. + +`` is the ledger fingerprint that will be used for staking. In GUI, the value in menu `Settings -> Option -> Main -> Select Ledger device for staking`. you can also get the fingerprint for the device by running `./hwi.py enumerate` from the command line in the HWI folder. + +`` is the name of the hardware device wallet that was created. + diff --git a/doc/sparknet-guide.md b/doc/sparknet-guide.md new file mode 100644 index 0000000000..ec6a50e3f9 --- /dev/null +++ b/doc/sparknet-guide.md @@ -0,0 +1,239 @@ +# Qtum Sparknet Usage and Information + +Qtum is a decentralized blockchain project built on Bitcoin's UTXO model, but with support for Ethereum Virtual Machine based smart contracts. It achieves this through the revolutionary Account Abstraction Layer. For more general information about Qtum as well as links to join our community, go to https://qtum.org + +Welcome to Qtum Sparknet, the first public testnet for the Qtum blockchain. Sparknet is designed primarily for developers, and as such documentation at this point will be technical and suited more for developers. The mainnet is expected to be released in September and will be suited for the general public. Testnet tokens do not hold any value and should not be traded for any monetary instruments. The testnet can be reset or forked at anytime as deemed necessary for development. Sparknet does not include support for Mutualized Proof Of Stake, or for the Decentralized Governance Protocol. Both of these features are implemented, and their code is available on alternative branches (check the pull requests), but have not been tested and proven stable enough to include in this testnet. They will be implemented in the 2nd public testnet for Qtum. + +# Using Smart Contracts with Qtum + +The smart contract interface in Qtum still requires some technical knowledge. The GUI is not completed yet, so all smart contract interation must happen either using `qtum-cli` at the command line, or in the debug window of `qtum-qt`. + +To demonstrate how to deploy and interact with a simple we will use this contract: + + pragma solidity ^0.4.0; + + contract QtumTest { + uint storedNumber; + function QtumTest() { + storedNumber=1; + } + function setNumber(uint number) public{ + storedNumber = number; + } + function logNumber() constant public{ + log1("storedNumber", uintToBytes(storedNumber)); + } + function returnNumber() constant public returns (uint){ + return storedNumber; + } + function deposit() public payable{ + } + function withdraw() public{ + if(!msg.sender.send(this.balance)){ + throw; + } + } + //utility function + function uintToBytes(uint v) constant returns (bytes32 ret) { + if (v == 0) { + ret = '0'; + } + else { + while (v > 0) { + ret = bytes32(uint(ret) / (2 ** 8)); + ret |= bytes32(((v % 10) + 48) * 2 ** (8 * 31)); + v /= 10; + } + } + return ret; + } + } + +It compiles to the following EVM bytecode + + 6060604052341561000c57fe5b5b60016000819055505b5b6102bd806100266000396000f30060606040523615610076576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633450bd6a146100785780633ccfd60b1461009e5780633fb5c1cb146100b057806394e8767d146100d05780639f2c436f1461010c578063d0e30db01461011e575bfe5b341561008057fe5b610088610128565b6040518082815260200191505060405180910390f35b34156100a657fe5b6100ae610133565b005b34156100b857fe5b6100ce6004808035906020019091905050610190565b005b34156100d857fe5b6100ee600480803590602001909190505061019b565b60405180826000191660001916815260200191505060405180910390f35b341561011457fe5b61011c610246565b005b61012661028e565b005b600060005490505b90565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051809050600060405180830381858888f19350505050151561018d57610000565b5b565b806000819055505b50565b600060008214156101ce577f3000000000000000000000000000000000000000000000000000000000000000905061023d565b5b600082111561023c5761010081600190048115156101e957fe5b0460010290507f01000000000000000000000000000000000000000000000000000000000000006030600a8481151561021e57fe5b06010260010281179050600a8281151561023457fe5b0491506101cf565b5b8090505b919050565b61025160005461019b565b6000191660405180807f73746f7265644e756d6265720000000000000000000000000000000000000000815250600c01905060405180910390a15b565b5b5600a165627a7a72305820326efcd34df5fdba07e7a1afe7ffd4b42873ef749ae9a5915db46fd20b9c251c0029 + +And finally, has the following JSON interface file: + + [{"constant":true,"inputs":[],"name":"returnNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"number","type":"uint256"}],"name":"setNumber","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"v","type":"uint256"}],"name":"uintToBytes","outputs":[{"name":"ret","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"logNumber","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}] + +This info can easily be retrieved for any contract by using [Browser Solidity](https://ethereum.github.io/browser-solidity/), inputing your contract's source code, and then on the right hand side clicking "contract details" + +(note, if using the debug window in the Qtum Qt application, don't include `./qtum-cli` in the commands) + +First, we need to deploy the contract: + + ./qtum-cli createcontract 6060604052341561000c57fe5b5b60016000819055505b5b6102bd806100266000396000f30060606040523615610076576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633450bd6a146100785780633ccfd60b1461009e5780633fb5c1cb146100b057806394e8767d146100d05780639f2c436f1461010c578063d0e30db01461011e575bfe5b341561008057fe5b610088610128565b6040518082815260200191505060405180910390f35b34156100a657fe5b6100ae610133565b005b34156100b857fe5b6100ce6004808035906020019091905050610190565b005b34156100d857fe5b6100ee600480803590602001909190505061019b565b60405180826000191660001916815260200191505060405180910390f35b341561011457fe5b61011c610246565b005b61012661028e565b005b600060005490505b90565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051809050600060405180830381858888f19350505050151561018d57610000565b5b565b806000819055505b50565b600060008214156101ce577f3000000000000000000000000000000000000000000000000000000000000000905061023d565b5b600082111561023c5761010081600190048115156101e957fe5b0460010290507f01000000000000000000000000000000000000000000000000000000000000006030600a8481151561021e57fe5b06010260010281179050600a8281151561023457fe5b0491506101cf565b5b8090505b919050565b61025160005461019b565b6000191660405180807f73746f7265644e756d6265720000000000000000000000000000000000000000815250600c01905060405180910390a15b565b5b5600a165627a7a72305820326efcd34df5fdba07e7a1afe7ffd4b42873ef749ae9a5915db46fd20b9c251c0029 300000 + +Note that the last number is the gas limit for this transaction. The default value is not large enough for this contract, so we increase it to 300,000 gas. + +This should result in something like so: + + { + "txid": "72b0e0576d289c1e4e6c777431e4845f77d0884d3b3cff0387a5f4a1a3a874ea", + "sender": "qZbjaE8N18ZU1m7851G7QGhvxKL74SRBTt", + "hash160": "aff3e34ab836edb8d214a993d9da105915e4a6e9", + "address": "5bde092dbecb84ea1a229b4c5b25dfc9cdc674d9" + } + + +Now, you should store the `address` in a variable so it's easy to track: + + export CONTRACT=5bde092dbecb84ea1a229b4c5b25dfc9cdc674d9 + +Now wait for your contract to be included in a block. You should be able to confirm it made it into a block by using: + + ./qtum-cli getaccountinfo $CONTRACT + +If you get a message saying "Address does not exist", then either your transaction has not yet been included in a block (you can confirm this with `getrawtransaction` and your txid), or you did not provide enough gas for the contract to be executed and persisted into the blockchain. If the contract was successfully executed and persisted in the blockchain, you should see something like this: + + { + "address": "5bde092dbecb84ea1a229b4c5b25dfc9cdc674d9", + "balance": 0, + "storage": { + "290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": { + "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000001" + } + }, + "code": "..." + } + + +In order to interact with the contract, you must create raw ABI data from the interface JSON file. The easiest tool to assist in this is ethabi, https://github.com/paritytech/ethabi + +Make sure the JSON file is saved somewhere, we will call it interface.json. + +In order to get the `storedNumber` variable we use the `returnNumber()` function. We can construct the ABI values by using ethabi: + + ethabi encode function ~/interface.json returnNumber + +The result of this is: + + 3450bd6a + +Now, because we are not changing state, we use `callcontract`: + + ./qtum-cli callcontract $CONTRACT 3450bd6a + +This results in a lot of data that can be useful in different contexts (including gas estimates), but we are only concerned about the `output` field, which is the value of `storedNumber` + + { + "address": "5bde092dbecb84ea1a229b4c5b25dfc9cdc674d9", + "executionResult": { + "gasUsed": 21664, + "excepted": "None", + "newAddress": "5bde092dbecb84ea1a229b4c5b25dfc9cdc674d9", + "output": "0000000000000000000000000000000000000000000000000000000000000001", + "codeDeposit": 0, + "gasRefunded": 0, + "depositSize": 0, + "gasForDeposit": 0 + }, + "transactionReceipt": { + "stateRoot": "ffbeb0377d43c6ed443a2840259ff5ead5158016ab54d55ef21b7b11aa71947f", + "gasUsed": 21664, + "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "log": [ + ] + } + } + +To change the storedNumber we can do an on-chain execution using `sendtocontract`. First, we need the ABI data: + + ethabi encode function ~/interface.json setNumber -p 123456 --lenient + 3fb5c1cb000000000000000000000000000000000000000000000000000000000001e240 + +Note we use --lenient so that we do not need to provide a full 256bit value as a parameter. Now, we can execute the contract directly: + + ./qtum-cli sendtocontract $CONTRACT 3fb5c1cb000000000000000000000000000000000000000000000000000000000001e240 + +Afterwards, we can call `returnNumber()` again and check the `output` field: + + "output": "000000000000000000000000000000000000000000000000000000000001e240", + +This is 123456 encoded as hex. + +You can also use the `logNumber()` function in order to generate logs. If your node was started with `-record-log-opcodes`, then the file `vmExecLogs.json` will contain any log operations that occur on the blockchain. This is what is used for events on the Ethereum blockchain, and eventually it is our intention to bring similar functionality to Qtum. + +You can also deposit and withdraw coins from this test contract using the `deposit()` and `withdraw()` functions. + +The ABI value for `deposit` is d0e30db0 and the ABI value for `withdraw` is 3ccfd60b + +This will send 10 tokens to the contract: + + ./qtum-cli sendtocontract $CONTRACT d0e30db0 10 + +And then, to withdraw them it's also very simple: + + ./qtum-cli sendtocontract $CONTRACT 3ccfd60b + +If you want to control the exact address that the contract sends coins to, you can also explicitly specify the sender. Note that you must be capable of sending coins from that address (you can't use someone elses address). One of my wallet addresses is qZbjaE8N18ZU1m7851G7QGhvxKL74SRBTt, so I'll use that: + + ./qtum-cli sendtocontract $CONTRACT 3ccfd60b 0 190000 0.0000001 qZbjaE8N18ZU1m7851G7QGhvxKL74SRBTt + +Note that if you get the error "Sender address does not have any unspent outputs", then you should send some coins to that address (they must be spent in order to prove that you own that address). This can be accomplished with any amount of coins: + + ./qtum-cli sendtoaddress qZbjaE8N18ZU1m7851G7QGhvxKL74SRBTt 0.001 + +There is no need to wait for this transaction to confirm, it can be followed immediately by the sendtocontract command: + + ./qtum-cli sendtocontract $CONTRACT 3ccfd60b 0 190000 0.0000001 qZbjaE8N18ZU1m7851G7QGhvxKL74SRBTt + +When creating this contract transaction, nothing will immediately happen, when the transaction is put into a block though a new transaction will appear in a block which will send any coins owned by the contract to the pubkeyhash address qZbjaE8N18ZU1m7851G7QGhvxKL74SRBTt + +## FAQ + +* Q: "I used `createcontract`, but can't call my contract and it's not in listcontract" A: You probably did not provide enough gas for the contract's constructor to be executed and it's code persisted in the blockchain. The vm.log file should confirm this by saying how much gas was needed +* Q: "I sent a large amount of gas but I never got a refund" A: Refunds are generated from the coinstake transaction, so you must wait 500 blocks for the gas refund to mature before it can be spent again +* Q: "I used -reindex and now my node is taking forever to resync" A: Currently when doing a reindex, all contracts are reprocessed, so in a chain with many contract executions this can add up to a significant amount of time. This will be made faster in the future, as well as the initial syncing speed of nodes +* Q: "I think I found a bug in Qtum" A: Please report any bugs at https://github.com/qtumproject/qtum/issues + + + +# New Qtum RPC Commands + +Qtum supports all of the RPC commands supported by Bitcoin Core, but also includes the following commands unique to Qtum: + +* `createcontract` - This will create and deploy a new smart contract to the Qtum blockchain. This requires gas. +* `callcontract` - This will interact with an already deployed smart contract on the Qtum blockchain, with all computation taking place off-chain and no persistence to the blockchain. This does not require gas +* `sendtocontract` - This will interact with an already deployed smart contract on the Qtum blockchain. All computation takes place on-chain and any state changes will be persisted to the blockchain. This allows tokens to be sent to a smart contract. This requires gas. +* `getaccountinfo` - This will show some low level information about a contract, including the contract's bytecode, stored data, and balance on the blockchain. +* `listcontracts` - This will output a list of currently deployed contract addresses with their respective balance. This RPC call may change or be removed in the future. +* `reservebalance` - This will reserve a set amount of coins so that they do not participate in staking. If you reserve as many or more coins than are in your wallet, then you will not participate at all in staking and block creation for the network. +* `getstakinginfo` - This will show some info about the current node's staking status, including network difficulty and expected time (in seconds) until staking a new block. +* `gethexaddress` - This will convert a standard Base58 pubkeyhash address to a hex address for use in smart contracts +* `fromhexaddress` - this will convert a hex address used in smart contracts to a standard Base58 pubkeyhash address + + +# New Qtum Command Line Arguments + +Qtum supports all of the usual command line arguments that Bitcoin Core supports. In addition it adds the following new command line arguments: + +* `-record-log-opcodes` - This will create a new log file in the Qtum data directory (usually ~/.qtum) named vmExecLogs.json, where any EVM LOG opcode is logged along with topics and data that the contract requested be logged. + +# Untested features + +Some features included in Bitcoin Core have not been tested in it's porting to Qtum. This includes: + +* Pruning + +# EVM Smart Contract Changes and Limitations + +Because of Qtum's underlying technical differences, there are a few operations that can have different results or limitations when executed in Qtum than when compared to Ethereum. + +These include the following, though there may be others introduced in the future: + +* The gas schedule for Qtum is different from Ethereum. Certain operations are more or less expensive. As such, gas cost estimators designed for Ethereum will not give accurate results for Qtum. We will develop our own gas estimating tools as well as fully documenting these differences at a later date. +* `block.coinbase` or the `COINBASE` opcode currently is not supported and will only return 0. When MPoS is released in the 2nd testnet this should be functioning as expected +* `block.number` will return the previous block height before this block containing the contract's execution +* `block.difficulty` will return the previous block's difficulty +* `block.timestamp will return the previous block's timestamp +* `block.blockhash(n)` will return 0 when n is the current block height (`block.number+1`), similar to Ethereum +* `sender` will return 0 when the coins spent (`vin[0].prevout`) are from a non-standard transaction. It will return the pubkeyhash 160bit address when spent from a pubkey or pubkeyhash transaction +* Coins can be sent to either contracts or pubkeyhash addresses. When coins are sent to a non-existent contract address, the coins will automatically be sent to a pubkeyhash address instead. +* Only 1000 vouts can be generated from a single contract execution. Sending coins to the same contract multiple times results in a single vout being created, so the limitation is effectively that coins can only be sent to up to 1000 unique contract or pubkeyhash addresses, including balance changes between contracts. If this limit is exceeded, an Out Of Gas exception is generated and all state changes are reverted. +* Contract executions can not happen within coinbase or coinstake transactions + +Additional documents for the overall design and expected results of various operations is available at the ITD repository here: https://github.com/qtumproject/qtum-itds + + diff --git a/share/pixmaps/qtumtestnet128.png b/share/pixmaps/qtumtestnet128.png new file mode 100644 index 0000000000..b2bbe16cea Binary files /dev/null and b/share/pixmaps/qtumtestnet128.png differ diff --git a/src/Makefile.cryptopp.include b/src/Makefile.cryptopp.include new file mode 100644 index 0000000000..186cf59590 --- /dev/null +++ b/src/Makefile.cryptopp.include @@ -0,0 +1,146 @@ +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +LIBCRYPTOPP_INT = cryptopp/libcryptopp.a + +EXTRA_LIBRARIES += $(LIBCRYPTOPP_INT) + +LIBCRYPTOPP += $(LIBCRYPTOPP_INT) + +CRYPTOPP_CPPFLAGS = -I$(srcdir)/cryptopp/include + +CRYPTOPP_CPPFLAGS_INT = +CRYPTOPP_CPPFLAGS_INT += -I$(srcdir)/cryptopp +CRYPTOPP_CPPFLAGS_INT += $(CRYPTOPP_TARGET_FLAGS) + +cryptopp_libcryptopp_a_CPPFLAGS = $(AM_CPPFLAGS) $(CRYPTOPP_CPPFLAGS_INT) $(CRYPTOPP_CPPFLAGS) +# TODO, don't assume x86 +cryptopp_libcryptopp_a_CXXFLAGS = $(AM_CXXFLAGS) -DNDEBUG -fPIC -O2 -g2 + +cryptopp_libcryptopp_a_SOURCES= +cryptopp_libcryptopp_a_SOURCES += cryptopp/cryptlib.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/cpu.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/integer.cpp + +cryptopp_libcryptopp_a_SOURCES += cryptopp/algebra.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/algparam.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/asn.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/basecode.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/dsa.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/des.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/dessp.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/dll.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/ec2n.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/eccrypto.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/ecp.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/eprecomp.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/filters.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/fips140.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/gf2n.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/gfpcrypt.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/hex.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/hmac.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/hrtimer.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/iterhash.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/keccak.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/misc.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/modes.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/mqueue.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/nbtheory.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/oaep.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/osrng.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/polynomi.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/pubkey.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/queue.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/randpool.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/rdtables.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/rijndael.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/rng.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/sha.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/strciphr.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/winpipes.cpp +cryptopp_libcryptopp_a_SOURCES += cryptopp/sha3.cpp + +cryptopp_libcryptopp_a_SOURCES += cryptopp/cryptlib.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/cpu.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/integer.h + +cryptopp_libcryptopp_a_SOURCES += cryptopp/algebra.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/algparam.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/asn.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/basecode.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/dsa.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/des.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/dll.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/ec2n.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/eccrypto.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/ecp.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/eprecomp.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/filters.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/fips140.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/gf2n.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/gfpcrypt.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/hex.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/hmac.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/hrtimer.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/iterhash.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/keccak.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/misc.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/modes.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/mqueue.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/nbtheory.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/oaep.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/osrng.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/polynomi.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/pubkey.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/queue.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/randpool.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/rijndael.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/rng.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/sha.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/strciphr.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/winpipes.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/sha3.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/aes.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/factory.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/config.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/dmac.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/drbg.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/esign.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/fhmqv.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/hkdf.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/hmqv.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/lubyrack.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/mersenne.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/modarith.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/modexppc.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/nr.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/pwdbased.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/secblock.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/siphash.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/trunhash.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/validate.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/words.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/seckey.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/stdcpp.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/trap.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/smartptr.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/simple.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/argnames.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/dh.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/mqv.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/ecpoint.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/fltrimpl.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/oids.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/ossig.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/pch.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/cbcmac.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/trdlocal.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/ccm.h +cryptopp_libcryptopp_a_SOURCES += cryptopp/*.h + +if TARGET_WINDOWS +else +endif + diff --git a/src/Makefile.libff.include b/src/Makefile.libff.include new file mode 100644 index 0000000000..98b4ae9cb0 --- /dev/null +++ b/src/Makefile.libff.include @@ -0,0 +1,122 @@ +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +LIBFF_INT = libff/libff.a + +EXTRA_LIBRARIES += $(LIBFF_INT) + +LIBFF += $(LIBFF_INT) + +LIBFF_CPPFLAGS += -I$(srcdir)/cryptopp/include $(GMP_CFLAGS) + +LIBFF_CPPFLAGS_INT = +LIBFF_CPPFLAGS_INT += -I$(srcdir)/libff +LIBFF_CPPFLAGS_INT += $(LIBFF_TARGET_FLAGS) + +libff_libff_a_CPPFLAGS = $(AM_CPPFLAGS) $(LIBFF_CPPFLAGS_INT) $(LIBFF_CPPFLAGS) -DCURVE_ALT_BN128 -DNO_PROCPS +libff_libff_a_CXXFLAGS = $(AM_CXXFLAGS) -DNDEBUG -fPIC -O2 -g2 + +libff_libff_a_SOURCES= +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_g1.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_g1.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_g2.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_g2.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_init.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_pairing.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_pairing.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_pp.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp + +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_g1.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_g1.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_g2.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_g2.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_init.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_init.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_pairing.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_pairing.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_pp.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/edwards/edwards_pp.hpp + +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_g1.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_g1.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_g2.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_g2.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_init.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_pairing.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_pairing.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_pp.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt4/mnt4_pp.hpp + +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_g1.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_g1.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_g2.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_g2.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_init.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_init.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_pairing.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_pairing.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_pp.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt6/mnt6_pp.hpp + +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt46_common.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/mnt/mnt46_common.hpp + +libff_libff_a_SOURCES += libff/libff/algebra/curves/tests/test_bilinearity.cpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/tests/test_groups.cpp + +libff_libff_a_SOURCES += libff/libff/algebra/curves/curve_utils.hpp +libff_libff_a_SOURCES += libff/libff/algebra/curves/curve_utils.tcc + +libff_libff_a_SOURCES += libff/libff/algebra/exponentiation/exponentiation.hpp +libff_libff_a_SOURCES += libff/libff/algebra/exponentiation/exponentiation.tcc + +libff_libff_a_SOURCES += libff/libff/algebra/fields/bigint.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/bigint.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/field_utils.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/field_utils.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp2.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp2.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp3.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp3.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp4.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp4.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp6_2over3.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp6_2over3.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp6_3over2.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp6_3over2.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp12_2over3over2.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp12_2over3over2.hpp +libff_libff_a_SOURCES += libff/libff/algebra/fields/fp_aux.tcc +libff_libff_a_SOURCES += libff/libff/algebra/fields/tests/test_fields.cpp + +libff_libff_a_SOURCES += libff/libff/algebra/scalar_multiplication/multiexp.tcc +libff_libff_a_SOURCES += libff/libff/algebra/scalar_multiplication/multiexp.hpp +libff_libff_a_SOURCES += libff/libff/algebra/scalar_multiplication/wnaf.tcc +libff_libff_a_SOURCES += libff/libff/algebra/scalar_multiplication/wnaf.hpp + + +libff_libff_a_SOURCES += libff/libff/common/default_types/ec_pp.hpp +libff_libff_a_SOURCES += libff/libff/common/double.cpp +libff_libff_a_SOURCES += libff/libff/common/double.hpp +libff_libff_a_SOURCES += libff/libff/common/profiling.cpp +libff_libff_a_SOURCES += libff/libff/common/profiling.hpp +libff_libff_a_SOURCES += libff/libff/common/rng.tcc +libff_libff_a_SOURCES += libff/libff/common/rng.hpp +libff_libff_a_SOURCES += libff/libff/common/serialization.tcc +libff_libff_a_SOURCES += libff/libff/common/serialization.hpp +libff_libff_a_SOURCES += libff/libff/common/template_utils.hpp +libff_libff_a_SOURCES += libff/libff/common/utils.cpp +libff_libff_a_SOURCES += libff/libff/common/utils.hpp +libff_libff_a_SOURCES += libff/libff/common/utils.tcc + + + + + + diff --git a/src/consensus/consensus.cpp b/src/consensus/consensus.cpp new file mode 100644 index 0000000000..52609f639a --- /dev/null +++ b/src/consensus/consensus.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */ +unsigned int dgpMaxBlockSerSize = 8000000; +/** The maximum allowed weight for a block, see BIP 141 (network rule) */ +unsigned int dgpMaxBlockWeight = 8000000; + +unsigned int dgpMaxBlockSize = 2000000; // qtum + +/** The maximum allowed number of signature check operations in a block (network rule) */ +int64_t dgpMaxBlockSigOps = 80000; + +unsigned int dgpMaxProtoMsgLength = 8000000; + +unsigned int dgpMaxTxSigOps = 16000; + +void updateBlockSizeParams(unsigned int newBlockSize){ + unsigned int newSizeForParams=WITNESS_SCALE_FACTOR*newBlockSize; + dgpMaxBlockSerSize=newSizeForParams; + dgpMaxBlockWeight=newSizeForParams; + dgpMaxBlockSigOps=(int64_t)(newSizeForParams/100); + dgpMaxTxSigOps = (unsigned int)(dgpMaxBlockSigOps/5); + dgpMaxProtoMsgLength=newSizeForParams; +} diff --git a/src/eth_client/libdevcore/Address.cpp b/src/eth_client/libdevcore/Address.cpp new file mode 100644 index 0000000000..e1e55d6384 --- /dev/null +++ b/src/eth_client/libdevcore/Address.cpp @@ -0,0 +1,11 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "Address.h" + +namespace dev +{ +Address const ZeroAddress; +Address const MaxAddress{"0xffffffffffffffffffffffffffffffffffffffff"}; +Address const SystemAddress{"0xfffffffffffffffffffffffffffffffffffffffe"}; +} diff --git a/src/eth_client/libdevcore/Address.h b/src/eth_client/libdevcore/Address.h new file mode 100644 index 0000000000..71aa54fc57 --- /dev/null +++ b/src/eth_client/libdevcore/Address.h @@ -0,0 +1,36 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// This file defines Address alias for FixedHash of 160 bits and some +/// special Address constants. + +#pragma once + +#include "FixedHash.h" + +namespace dev +{ + +/// 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; + +/// A hash set of Ethereum addresses. +using AddressHash = std::unordered_set; + +/// The zero address. +extern Address const ZeroAddress; + +/// The last address. +extern Address const MaxAddress; + +/// The SYSTEM address. +extern Address const SystemAddress; + +} + diff --git a/src/eth_client/libdevcore/Assertions.h b/src/eth_client/libdevcore/Assertions.h new file mode 100644 index 0000000000..bf8864fe3a --- /dev/null +++ b/src/eth_client/libdevcore/Assertions.h @@ -0,0 +1,84 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// Assertion handling. +#pragma once + +#include +#include + +namespace dev +{ + +#if defined(_MSC_VER) +#define ETH_FUNC __FUNCSIG__ +#elif defined(__GNUC__) +#define ETH_FUNC __PRETTY_FUNCTION__ +#else +#define ETH_FUNC __func__ +#endif + +#define asserts(A) ::dev::assertAux(A, #A, __LINE__, __FILE__, ETH_FUNC) +#define assertsEqual(A, B) ::dev::assertEqualAux(A, B, #A, #B, __LINE__, __FILE__, ETH_FUNC) + +inline bool assertAux(bool _a, char const* _aStr, unsigned _line, char const* _file, char const* _func) +{ + if (!_a) + std::cerr << "Assertion failed:" << _aStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; + return !_a; +} + +template +inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char const* _bStr, unsigned _line, char const* _file, char const* _func) +{ + bool c = _a == _b; + if (!c) + { + std::cerr << "Assertion failed: " << _aStr << " == " << _bStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; + std::cerr << " Fail equality: " << _a << "==" << _b << std::endl; + } + return !c; +} + +/// Assertion that throws an exception containing the given description if it is not met. +/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); +/// Do NOT supply an exception object as the second parameter. +#define assertThrow(_condition, _ExceptionType, _description) \ + ::dev::assertThrowAux<_ExceptionType>(_condition, _description, __LINE__, __FILE__, ETH_FUNC) + +using errinfo_comment = boost::error_info; + +template +inline void assertThrowAux( + bool _condition, + ::std::string const& _errorDescription, + unsigned _line, + char const* _file, + char const* _function +) +{ + if (!_condition) + ::boost::throw_exception( + _ExceptionType() << + ::dev::errinfo_comment(_errorDescription) << + ::boost::throw_function(_function) << + ::boost::throw_file(_file) << + ::boost::throw_line(_line) + ); +} + +template +inline void assertThrowAux( + void const* _pointer, + ::std::string const& _errorDescription, + unsigned _line, + char const* _file, + char const* _function +) +{ + assertThrowAux<_ExceptionType>(_pointer != nullptr, _errorDescription, _line, _file, _function); +} + +} diff --git a/src/eth_client/libdevcore/Common.cpp b/src/eth_client/libdevcore/Common.cpp new file mode 100644 index 0000000000..6cc00e9e50 --- /dev/null +++ b/src/eth_client/libdevcore/Common.cpp @@ -0,0 +1,123 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "Common.h" +#include "Exceptions.h" +#include "Log.h" + +#if defined(_WIN32) +#include +#endif + +using namespace std; + +namespace dev +{ +bytes const NullBytes; +std::string const EmptyString; + +void InvariantChecker::checkInvariants(HasInvariants const* _this, char const* _fn, char const* _file, int _line, bool _pre) +{ + if (!_this->invariants()) + { + cwarn << (_pre ? "Pre" : "Post") << "invariant failed in" << _fn << "at" << _file << ":" << _line; + BOOST_THROW_EXCEPTION(FailedInvariant()); + } +} + +TimerHelper::~TimerHelper() +{ + auto e = std::chrono::high_resolution_clock::now() - m_t; + if (!m_ms || e > chrono::milliseconds(m_ms)) + clog(VerbosityDebug, "timer") + << m_id << " " << chrono::duration_cast(e).count() << " ms"; +} + +int64_t utcTime() +{ + // TODO: Fix if possible to not use time(0) and merge only after testing in all platforms + // time_t t = time(0); + // return mktime(gmtime(&t)); + return time(0); +} + +string inUnits(bigint const& _b, strings const& _units) +{ + ostringstream ret; + u256 b; + if (_b < 0) + { + ret << "-"; + b = (u256)-_b; + } + else + b = (u256)_b; + + u256 biggest = 1; + for (unsigned i = _units.size() - 1; !!i; --i) + biggest *= 1000; + + if (b > biggest * 1000) + { + ret << (b / biggest) << " " << _units.back(); + return ret.str(); + } + ret << setprecision(3); + + u256 unit = biggest; + for (auto it = _units.rbegin(); it != _units.rend(); ++it) + { + auto i = *it; + if (i != _units.front() && b >= unit) + { + ret << (double(b / (unit / 1000)) / 1000.0) << " " << i; + return ret.str(); + } + else + unit /= 1000; + } + ret << b << " " << _units.front(); + return ret.str(); +} + +/* +The equivalent of setlocale(LC_ALL, “C”) is called before any user code is run. +If the user has an invalid environment setting then it is possible for the call +to set locale to fail, so there are only two possible actions, the first is to +throw a runtime exception and cause the program to quit (default behaviour), +or the second is to modify the environment to something sensible (least +surprising behaviour). + +The follow code produces the least surprising behaviour. It will use the user +specified default locale if it is valid, and if not then it will modify the +environment the process is running in to use a sensible default. This also means +that users do not need to install language packs for their OS. +*/ +void setDefaultOrCLocale() +{ +#if __unix__ + if (!setlocale(LC_ALL, "")) + setenv("LC_ALL", "C", 1); +#endif + +#if defined(_WIN32) + // Change the code page from the default OEM code page (437) so that UTF-8 characters are + // displayed correctly in the console. + SetConsoleOutputCP(CP_UTF8); +#endif +} + +bool ExitHandler::s_shouldExit = false; + +bool isTrue(std::string const& _m) +{ + return _m == "on" || _m == "yes" || _m == "true" || _m == "1"; +} + +bool isFalse(std::string const& _m) +{ + return _m == "off" || _m == "no" || _m == "false" || _m == "0"; +} + +} // namespace dev diff --git a/src/eth_client/libdevcore/Common.h b/src/eth_client/libdevcore/Common.h new file mode 100644 index 0000000000..52fd7c680b --- /dev/null +++ b/src/eth_client/libdevcore/Common.h @@ -0,0 +1,317 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// Very common stuff (i.e. that every other header needs except vector_ref.h). +#pragma once + +// way too many unsigned to size_t warnings in 32 bit build +#ifdef _M_IX86 +#pragma warning(disable:4244) +#endif + +#if _MSC_VER && _MSC_VER < 1900 +#define _ALLOW_KEYWORD_MACROS +#define noexcept throw() +#endif + +#ifdef __INTEL_COMPILER +#pragma warning(disable:3682) //call through incomplete class +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#pragma warning(pop) +#pragma GCC diagnostic pop +#include "vector_ref.h" + +// CryptoPP defines byte in the global namespace, so must we. +using byte = uint8_t; + +#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} + +#define DEV_IF_THROWS(X) try{X;}catch(...) + +namespace dev +{ +using namespace boost::multiprecision::literals; + +extern std::string const EmptyString; + +// Binary data types. +using byte = uint8_t; +using bytes = std::vector; +using bytesRef = vector_ref; +using bytesConstRef = vector_ref; + +template +class secure_vector +{ +public: + secure_vector() {} + secure_vector(secure_vector const& /*_c*/) = default; // See https://github.com/ethereum/libweb3core/pull/44 + explicit secure_vector(size_t _size): m_data(_size) {} + explicit secure_vector(size_t _size, T _item): m_data(_size, _item) {} + explicit secure_vector(std::vector const& _c): m_data(_c) {} + explicit secure_vector(vector_ref _c): m_data(_c.data(), _c.data() + _c.size()) {} + explicit secure_vector(vector_ref _c): m_data(_c.data(), _c.data() + _c.size()) {} + ~secure_vector() { ref().cleanse(); } + + secure_vector& operator=(secure_vector const& _c) + { + if (&_c == this) + return *this; + + ref().cleanse(); + m_data = _c.m_data; + return *this; + } + std::vector& writable() { clear(); return m_data; } + std::vector const& makeInsecure() const { return m_data; } + + void clear() { ref().cleanse(); } + + vector_ref ref() { return vector_ref(&m_data); } + vector_ref ref() const { return vector_ref(&m_data); } + + size_t size() const { return m_data.size(); } + bool empty() const { return m_data.empty(); } + + void swap(secure_vector& io_other) { m_data.swap(io_other.m_data); } + +private: + std::vector m_data; +}; + +using bytesSec = secure_vector; + +// Numeric types. +using bigint = boost::multiprecision::number>; +using u8 = boost::multiprecision::number>; +using u64 = boost::multiprecision::number>; +using u128 = boost::multiprecision::number>; +using u256 = boost::multiprecision::number>; +using s256 = boost::multiprecision::number>; +using u160 = boost::multiprecision::number>; +using s160 = boost::multiprecision::number>; +using u512 = boost::multiprecision::number>; +using s512 = boost::multiprecision::number>; +using u256s = std::vector; +using u160s = std::vector; +using u256Set = std::set; +using u160Set = std::set; + +// Map types. +using StringMap = std::map; +using BytesMap = std::map; +using u256Map = std::map; +using HexMap = std::map; + +// Hash types. +using StringHashMap = std::unordered_map; +using u256HashMap = std::unordered_map; + +// String types. +using strings = std::vector; + +// Fixed-length string types. +using string32 = std::array; + +// Null/Invalid values for convenience. +extern bytes const NullBytes; +u256 constexpr Invalid256 = + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_cppui256; + +/// Interprets @a _u as a two's complement signed number and returns the resulting s256. +inline s256 u2s(u256 _u) +{ + static const bigint c_end = bigint(1) << 256; + if (boost::multiprecision::bit_test(_u, 255)) + return s256(-(c_end - _u)); + else + return s256(_u); +} + +/// @returns the two's complement signed representation of the signed number _u. +inline u256 s2u(s256 _u) +{ + static const bigint c_end = bigint(1) << 256; + if (_u >= 0) + return u256(_u); + else + return u256(c_end + _u); +} + +/// Converts given int to a string and appends one of a series of units according to its size. +std::string inUnits(bigint const& _b, strings const& _units); + +/// @returns the smallest n >= 0 such that (1 << n) >= _x +inline unsigned int toLog2(u256 _x) +{ + unsigned ret; + for (ret = 0; _x >>= 1; ++ret) {} + return ret; +} + +template inline u256 exp10() +{ + return exp10() * u256(10); +} + +template <> inline u256 exp10<0>() +{ + return u256(1); +} + +/// Converts given multiprecision number to standard number type +template uint64_t toUint64(T _u) +{ + return static_cast(u64(_u)); +} + +template uint8_t toUint8(T _u) +{ + return static_cast(u8(_u)); +} + +/// @returns the absolute distance between _a and _b. +template +inline N diff(N const& _a, N const& _b) +{ + return std::max(_a, _b) - std::min(_a, _b); +} + +/// RAII utility class whose destructor calls a given function. +class ScopeGuard +{ +public: + ScopeGuard(std::function _f): m_f(_f) {} + ~ScopeGuard() { m_f(); } + +private: + std::function m_f; +}; + +/// Inheritable for classes that have invariants. +class HasInvariants +{ +public: + /// Reimplement to specify the invariants. + virtual bool invariants() const = 0; +}; + +/// RAII checker for invariant assertions. +class InvariantChecker +{ +public: + InvariantChecker(HasInvariants* _this, char const* _fn, char const* _file, int _line): m_this(_this), m_function(_fn), m_file(_file), m_line(_line) { checkInvariants(_this, _fn , _file, _line, true); } + ~InvariantChecker() { checkInvariants(m_this, m_function, m_file, m_line, false); } + /// Check invariants are met, throw if not. + static void checkInvariants(HasInvariants const* _this, char const* _fn, char const* _file, int line, bool _pre); + +private: + HasInvariants const* m_this; + char const* m_function; + char const* m_file; + int m_line; +}; + +/// Scope guard for invariant check in a class derived from HasInvariants. +#if ETH_DEBUG +#define DEV_INVARIANT_CHECK ::dev::InvariantChecker __dev_invariantCheck(this, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__) +#define DEV_INVARIANT_CHECK_HERE ::dev::InvariantChecker::checkInvariants(this, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, true) +#else +#define DEV_INVARIANT_CHECK (void)0; +#define DEV_INVARIANT_CHECK_HERE (void)0; +#endif + +/// Simple scope-based timer helper. +class TimerHelper +{ +public: + TimerHelper(std::string const& _id, unsigned _msReportWhenGreater = 0): m_t(std::chrono::high_resolution_clock::now()), m_id(_id), m_ms(_msReportWhenGreater) {} + ~TimerHelper(); + +private: + std::chrono::high_resolution_clock::time_point m_t; + std::string m_id; + unsigned m_ms; +}; + +class Timer +{ +public: + Timer() { restart(); } + + std::chrono::high_resolution_clock::duration duration() const { return std::chrono::high_resolution_clock::now() - m_t; } + double elapsed() const { return std::chrono::duration_cast(duration()).count() / 1000000.0; } + void restart() { m_t = std::chrono::high_resolution_clock::now(); } + +private: + std::chrono::high_resolution_clock::time_point m_t; +}; + +#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(S, true); __eth_t.second; __eth_t.second = false) +#define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S) +#if defined(_MSC_VER) +#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__) +#else +#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__) +#endif + +#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(S, MS), true); __eth_t.second; __eth_t.second = false) +#define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS) +#if defined(_MSC_VER) +#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS) +#else +#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__PRETTY_FUNCTION__, MS) +#endif + +#ifdef _MSC_VER +// TODO. +#define DEV_UNUSED +#else +#define DEV_UNUSED __attribute__((unused)) +#endif + +enum class WithExisting: int +{ + Trust = 0, + Verify, + Rescue, + Kill +}; + +/// Get the current time in seconds since the epoch in UTC +int64_t utcTime(); + +void setDefaultOrCLocale(); + +static constexpr unsigned c_lineWidth = 160; + +static const auto c_steadyClockMin = std::chrono::steady_clock::time_point::min(); + +class ExitHandler +{ +public: + static void exitHandler(int) { s_shouldExit = true; } + bool shouldExit() const { return s_shouldExit; } + +private: + static bool s_shouldExit; +}; + +bool isTrue(std::string const& _m); +bool isFalse(std::string const& _m); +} // namespace dev diff --git a/src/eth_client/libdevcore/CommonData.cpp b/src/eth_client/libdevcore/CommonData.cpp new file mode 100644 index 0000000000..1b30690846 --- /dev/null +++ b/src/eth_client/libdevcore/CommonData.cpp @@ -0,0 +1,113 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include "CommonData.h" +#include + +#include "Exceptions.h" + +using namespace std; +using namespace dev; + +namespace +{ +int fromHexChar(char _i) noexcept +{ + 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; + return -1; +} +} + +bool dev::isHex(string const& _s) noexcept +{ + auto it = _s.begin(); + if (_s.compare(0, 2, "0x") == 0) + it += 2; + return std::all_of(it, _s.end(), [](char c){ return fromHexChar(c) != -1; }); +} + +std::string dev::escaped(std::string const& _s, bool _all) +{ + static const map prettyEscapes{{'\r', 'r'}, {'\n', 'n'}, {'\t', 't'}, {'\v', 'v'}}; + std::string ret; + ret.reserve(_s.size() + 2); + ret.push_back('"'); + for (auto i: _s) + if (i == '"' && !_all) + ret += "\\\""; + else if (i == '\\' && !_all) + ret += "\\\\"; + else if (prettyEscapes.count(i) && !_all) + { + ret += '\\'; + ret += prettyEscapes.find(i)->second; + } + else if (i < ' ' || _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; +} + + +bytes dev::fromHex(std::string const& _s, WhenError _throw) +{ + unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0; + std::vector ret; + ret.reserve((_s.size() - s + 1) / 2); + + if (_s.size() % 2) + { + int h = fromHexChar(_s[s++]); + if (h != -1) + ret.push_back(h); + else if (_throw == WhenError::Throw) + BOOST_THROW_EXCEPTION(BadHexCharacter()); + else + return bytes(); + } + for (unsigned i = s; i < _s.size(); i += 2) + { + int h = fromHexChar(_s[i]); + int l = fromHexChar(_s[i + 1]); + if (h != -1 && l != -1) + ret.push_back((byte)(h * 16 + l)); + else if (_throw == WhenError::Throw) + BOOST_THROW_EXCEPTION(BadHexCharacter()); + else + return bytes(); + } + return ret; +} + +bytes dev::asNibbles(bytesConstRef const& _s) +{ + std::vector ret; + ret.reserve(_s.size() * 2); + for (auto i: _s) + { + ret.push_back(i / 16); + ret.push_back(i % 16); + } + return ret; +} + +std::string dev::toString(string32 const& _s) +{ + std::string ret; + for (unsigned i = 0; i < 32 && _s[i]; ++i) + ret.push_back(_s[i]); + return ret; +} diff --git a/src/eth_client/libdevcore/CommonData.h b/src/eth_client/libdevcore/CommonData.h new file mode 100644 index 0000000000..d1dde6ae1c --- /dev/null +++ b/src/eth_client/libdevcore/CommonData.h @@ -0,0 +1,337 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// Shared algorithms and data types. +#pragma once + +#include +#include +#include +#include +#include +#include +#include "Common.h" + +namespace dev +{ + +// String conversion functions, mainly to/from hex/nibble/byte representations. + +enum class WhenError +{ + DontThrow = 0, + Throw = 1, +}; + +template +std::string toHex(Iterator _it, Iterator _end, std::string const& _prefix) +{ + typedef std::iterator_traits traits; + static_assert(sizeof(typename traits::value_type) == 1, "toHex needs byte-sized element type"); + + static char const* hexdigits = "0123456789abcdef"; + size_t off = _prefix.size(); + std::string hex(std::distance(_it, _end)*2 + off, '0'); + hex.replace(0, off, _prefix); + for (; _it != _end; _it++) + { + hex[off++] = hexdigits[(*_it >> 4) & 0x0f]; + hex[off++] = hexdigits[*_it & 0x0f]; + } + return hex; +} + +/// Convert a series of bytes to the corresponding hex string. +/// @example toHex("A\x69") == "4169" +template std::string toHex(T const& _data) +{ + return toHex(_data.begin(), _data.end(), ""); +} + +/// Convert a series of bytes to the corresponding hex string with 0x prefix. +/// @example toHexPrefixed("A\x69") == "0x4169" +template std::string toHexPrefixed(T const& _data) +{ + return toHex(_data.begin(), _data.end(), "0x"); +} + +/// Converts a (printable) ASCII hex string into the corresponding byte stream. +/// @example fromHex("41626261") == asBytes("Abba") +/// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception. +bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow); + +/// @returns true if @a _s is a hex string. +bool isHex(std::string const& _s) noexcept; + +/// @returns true if @a _hash is a hash conforming to FixedHash type @a T. +template static bool isHash(std::string const& _hash) +{ + return (_hash.size() == T::size * 2 || (_hash.size() == T::size * 2 + 2 && _hash.substr(0, 2) == "0x")) && isHex(_hash); +} + +/// 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 byte array ref 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(bytesConstRef _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(bytesConstRef 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 unsigned, u160, u256 or bigint. +template +inline void toBigEndian(T _val, Out& o_out) +{ + static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + for (auto i = o_out.size(); i != 0; _val >>= 8, i--) + { + T v = _val & (T)0xff; + o_out[i - 1] = (typename Out::value_type)(uint8_t)v; + } +} + +/// 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 unsigned, u160, u256 or bigint. +template +inline T fromBigEndian(_In const& _bytes) +{ + T ret = (T)0; + for (auto i: _bytes) + ret = (T)((ret << 8) | (byte)(typename std::make_unsigned::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 byte array just big enough to represent @a _val. +template +inline bytes toCompactBigEndian(T _val, unsigned _min = 0) +{ + static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + int i = 0; + for (T v = _val; v; ++i, v >>= 8) {} + bytes ret(std::max(_min, i), 0); + toBigEndian(_val, ret); + return ret; +} +inline bytes toCompactBigEndian(byte _val, unsigned _min = 0) +{ + return (_min || _val) ? bytes{ _val } : bytes{}; +} + +/// Convenience function for toBigEndian. +/// @returns a string just big enough to represent @a _val. +template +inline std::string toCompactBigEndianString(T _val, unsigned _min = 0) +{ + static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + int i = 0; + for (T v = _val; v; ++i, v >>= 8) {} + std::string ret(std::max(_min, i), '\0'); + toBigEndian(_val, ret); + return ret; +} + +inline std::string toCompactHex(u256 _val, unsigned _min = 0) +{ + return toHex(toCompactBigEndian(_val, _min)); +} + +inline std::string toCompactHexPrefixed(u256 _val, unsigned _min = 0) +{ + return toHexPrefixed(toCompactBigEndian(_val, _min)); +} + +// 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 +unsigned commonPrefix(T const& _t, _U const& _u) +{ + unsigned s = std::min(_t.size(), _u.size()); + for (unsigned i = 0;; ++i) + if (i == s || _t[i] != _u[i]) + return i; + return s; +} + +/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero. +template +inline unsigned bytesRequired(T _i) +{ + static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + unsigned i = 0; + for (; _i != 0; ++i, _i >>= 8) {} + return i; +} + +/// Trims a given number of elements from the front of a collection. +/// Only works for POD element types. +template +void trimFront(T& _t, unsigned _elements) +{ + static_assert(std::is_pod::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 +void pushFront(T& _t, _U _e) +{ + static_assert(std::is_pod::value, ""); + _t.push_back(_e); + memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e)); + _t[0] = _e; +} + +/// Concatenate the contents of a container onto a vector. +template +inline std::vector& operator+=(std::vector& _a, U const& _b) +{ + _a.insert(_a.end(), std::begin(_b), std::end(_b)); + return _a; +} + +/// Insert the contents of a container into a set +template +std::set& operator+=(std::set& _a, U const& _b) +{ + _a.insert(std::begin(_b), std::end(_b)); + return _a; +} + +/// Insert the contents of a container into an unordered_set +template +std::unordered_set& operator+=(std::unordered_set& _a, U const& _b) +{ + _a.insert(std::begin(_b), std::end(_b)); + return _a; +} + +/// Insert the contents of a container into a set +template std::set operator+(std::set _a, U const& _b) +{ + return _a += _b; +} + +/// Insert the contents of a container into an unordered_set +template std::unordered_set operator+(std::unordered_set _a, U const& _b) +{ + return _a += _b; +} + +/// Concatenate the contents of a container onto a vector +template std::vector operator+(std::vector _a, U const& _b) +{ + return _a += _b; +} + +/// Make normal string from fixed-length string. +std::string toString(string32 const& _s); + +template +std::vector keysOf(std::map const& _m) +{ + std::vector ret; + for (auto const& i: _m) + ret.push_back(i.first); + return ret; +} + +template +std::vector keysOf(std::unordered_map const& _m) +{ + std::vector ret; + for (auto const& i: _m) + ret.push_back(i.first); + return ret; +} + +template +std::vector valuesOf(std::map const& _m) +{ + std::vector ret; + ret.reserve(_m.size()); + for (auto const& i: _m) + ret.push_back(i.second); + return ret; +} + +template +std::vector valuesOf(std::unordered_map const& _m) +{ + std::vector ret; + ret.reserve(_m.size()); + for (auto const& i: _m) + ret.push_back(i.second); + return ret; +} + +template +bool contains(T const& _t, V const& _v) +{ + return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v); +} + +template +bool contains(std::unordered_set const& _set, V const& _v) +{ + return _set.find(_v) != _set.end(); +} + +template +bool contains(std::unordered_map const& _map, K const& _k) +{ + return _map.find(_k) != _map.end(); +} + +template +bool contains(std::set const& _set, V const& _v) +{ + return _set.find(_v) != _set.end(); +} + +template +bool contains(std::map const& _map, K const& _k) +{ + return _map.find(_k) != _map.end(); +} +} diff --git a/src/eth_client/libdevcore/CommonIO.cpp b/src/eth_client/libdevcore/CommonIO.cpp new file mode 100644 index 0000000000..675b37f232 --- /dev/null +++ b/src/eth_client/libdevcore/CommonIO.cpp @@ -0,0 +1,190 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "CommonIO.h" +#include +#include +#include +#include +#include +#if defined(_WIN32) +#include +#else +#include +#endif +#include "Exceptions.h" +#include +using namespace std; +using namespace dev; + +namespace fs = boost::filesystem; + +namespace dev +{ +namespace +{ +void createDirectoryIfNotExistent(boost::filesystem::path const& _path) +{ + if (!fs::exists(_path)) + { + fs::create_directories(_path); + DEV_IGNORE_EXCEPTIONS(fs::permissions(_path, fs::owner_all)); + } +} + +} // namespace + +string memDump(bytes const& _bytes, unsigned _width, bool _html) +{ + stringstream ret; + if (_html) + ret << "
";
+    for (unsigned i = 0; i < _bytes.size(); i += _width)
+    {
+        ret << hex << setw(4) << setfill('0') << i << " ";
+        for (unsigned j = i; j < i + _width; ++j)
+            if (j < _bytes.size())
+                if (_bytes[j] >= 32 && _bytes[j] < 127)
+                    if ((char)_bytes[j] == '<' && _html)
+                        ret << "<";
+                    else if ((char)_bytes[j] == '&' && _html)
+                        ret << "&";
+                    else
+                        ret << (char)_bytes[j];
+                else
+                    ret << '?';
+            else
+                ret << ' ';
+        ret << " ";
+        for (unsigned j = i; j < i + _width && j < _bytes.size(); ++j)
+            ret << setfill('0') << setw(2) << hex << (unsigned)_bytes[j] << " ";
+        ret << "\n";
+    }
+    if (_html)
+        ret << "
"; + return ret.str(); +} + +template +inline _T contentsGeneric(boost::filesystem::path const& _file) +{ + _T ret; + size_t const c_elementSize = sizeof(typename _T::value_type); + std::ifstream is(_file.string(), std::ifstream::binary); + if (!is) + return ret; + + // get length of file: + is.seekg(0, is.end); + streamoff length = is.tellg(); + if (length == 0) + return ret; // do not read empty file (MSVC does not like it) + is.seekg(0, is.beg); + + ret.resize((length + c_elementSize - 1) / c_elementSize); + is.read(const_cast(reinterpret_cast(ret.data())), length); + return ret; +} + +bytes contents(boost::filesystem::path const& _file) +{ + return contentsGeneric(_file); +} + +bytesSec contentsSec(boost::filesystem::path const& _file) +{ + bytes b = contentsGeneric(_file); + bytesSec ret(b); + bytesRef(&b).cleanse(); + return ret; +} + +string contentsString(boost::filesystem::path const& _file) +{ + return contentsGeneric(_file); +} + +void writeFile(boost::filesystem::path const& _file, bytesConstRef _data, bool _writeDeleteRename) +{ + if (_writeDeleteRename) + { + fs::path tempPath = appendToFilename(_file, "-%%%%%%"); // XXX should not convert to string for this + writeFile(tempPath, _data, false); + // will delete _file if it exists + fs::rename(tempPath, _file); + } + else + { + createDirectoryIfNotExistent(_file.parent_path()); + + std::ofstream s(_file.string(), ios::trunc | ios::binary); + s.write(reinterpret_cast(_data.data()), _data.size()); + if (!s) + BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file.string())); + DEV_IGNORE_EXCEPTIONS(fs::permissions(_file, fs::owner_read | fs::owner_write)); + } +} + +void copyDirectory(boost::filesystem::path const& _srcDir, boost::filesystem::path const& _dstDir) +{ + createDirectoryIfNotExistent(_dstDir); + + for (fs::directory_iterator file(_srcDir); file != fs::directory_iterator(); ++file) + fs::copy_file(file->path(), _dstDir / file->path().filename()); +} + +std::string getPassword(std::string const& _prompt) +{ +#if defined(_WIN32) + cout << _prompt << flush; + // Get current Console input flags + HANDLE hStdin; + DWORD fdwSaveOldMode; + if ((hStdin = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) + BOOST_THROW_EXCEPTION( + ExternalFunctionFailure() << errinfo_externalFunction("GetStdHandle")); + if (!GetConsoleMode(hStdin, &fdwSaveOldMode)) + BOOST_THROW_EXCEPTION( + ExternalFunctionFailure() << errinfo_externalFunction("GetConsoleMode")); + // Set console flags to no echo + if (!SetConsoleMode(hStdin, fdwSaveOldMode & (~ENABLE_ECHO_INPUT))) + BOOST_THROW_EXCEPTION( + ExternalFunctionFailure() << errinfo_externalFunction("SetConsoleMode")); + // Read the string + std::string ret; + std::getline(cin, ret); + // Restore old input mode + if (!SetConsoleMode(hStdin, fdwSaveOldMode)) + BOOST_THROW_EXCEPTION( + ExternalFunctionFailure() << errinfo_externalFunction("SetConsoleMode")); + return ret; +#else + struct termios oflags; + struct termios nflags; + char password[256]; + + // disable echo in the terminal + tcgetattr(fileno(stdin), &oflags); + nflags = oflags; + nflags.c_lflag &= ~ECHO; + nflags.c_lflag |= ECHONL; + + if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) + BOOST_THROW_EXCEPTION(ExternalFunctionFailure() << errinfo_externalFunction("tcsetattr")); + + printf("%s", _prompt.c_str()); + if (!fgets(password, sizeof(password), stdin)) + BOOST_THROW_EXCEPTION(ExternalFunctionFailure() << errinfo_externalFunction("fgets")); + password[strlen(password) - 1] = 0; + + // restore terminal + if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) + BOOST_THROW_EXCEPTION(ExternalFunctionFailure() << errinfo_externalFunction("tcsetattr")); + + + return password; +#endif +} + +} // namespace dev diff --git a/src/eth_client/libdevcore/CommonIO.h b/src/eth_client/libdevcore/CommonIO.h new file mode 100644 index 0000000000..3d987ffbbc --- /dev/null +++ b/src/eth_client/libdevcore/CommonIO.h @@ -0,0 +1,171 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// File & stream I/O routines. +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Common.h" +#include "CommonData.h" +#include + +namespace dev +{ + +/// Requests the user to enter a password on the console. +std::string getPassword(std::string const& _prompt); + +/// Retrieve and returns the contents of the given file. +/// If the file doesn't exist or isn't readable, returns an empty container / bytes. +bytes contents(boost::filesystem::path const& _file); +/// Secure variation. +bytesSec contentsSec(boost::filesystem::path const& _file); +/// Retrieve and returns the contents of the given file as a std::string. +/// If the file doesn't exist or isn't readable, returns an empty container / bytes. +std::string contentsString(boost::filesystem::path const& _file); + +/// Write the given binary data into the given file, replacing the file if it pre-exists. +/// Throws exception on error. +/// @param _writeDeleteRename useful not to lose any data: If set, first writes to another file in +/// the same directory and then moves that file. +void writeFile(boost::filesystem::path const& _file, bytesConstRef _data, bool _writeDeleteRename = false); +/// Write the given binary data into the given file, replacing the file if it pre-exists. +inline void writeFile(boost::filesystem::path const& _file, bytes const& _data, bool _writeDeleteRename = false) { writeFile(_file, bytesConstRef(&_data), _writeDeleteRename); } + +/// Non-recursively copies directory contents. +/// Throws boost::filesystem_error on error. +void copyDirectory(boost::filesystem::path const& _srcDir, boost::filesystem::path const& _dstDir); + +/// Nicely renders the given bytes to a string, optionally as HTML. +/// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line. +std::string memDump(bytes const& _bytes, unsigned _width = 8, bool _html = false); + +// 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 struct StreamOut { static std::ostream& bypass(std::ostream& _out, T const& _t) { _out << _t; return _out; } }; +template <> struct StreamOut { static std::ostream& bypass(std::ostream& _out, uint8_t const& _t) { _out << (int)_t; return _out; } }; + +inline std::ostream& operator<<(std::ostream& _out, bytes const& _e) { _out << toHexPrefixed(_e); return _out; } +template inline std::ostream& operator<<(std::ostream& _out, std::vector const& _e); +template inline std::ostream& operator<<(std::ostream& _out, std::array const& _e); +template inline std::ostream& operator<<(std::ostream& _out, std::set const& _e); +template inline std::ostream& operator<<(std::ostream& _out, std::unordered_set const& _e); + +#if defined(_WIN32) +template inline std::string toString(std::chrono::time_point const& _e, std::string const& _format = "%Y-%m-%d %H:%M:%S") +#else +template inline std::string toString(std::chrono::time_point const& _e, std::string const& _format = "%F %T") +#endif +{ + unsigned long milliSecondsSinceEpoch = std::chrono::duration_cast(_e.time_since_epoch()).count(); + auto const durationSinceEpoch = std::chrono::milliseconds(milliSecondsSinceEpoch); + std::chrono::time_point const tpAfterDuration(durationSinceEpoch); + + tm timeValue; + auto time = std::chrono::system_clock::to_time_t(tpAfterDuration); +#if defined(_WIN32) + gmtime_s(&timeValue, &time); +#else + gmtime_r(&time, &timeValue); +#endif + + unsigned const millisRemainder = milliSecondsSinceEpoch % 1000; + char buffer[1024]; + if (strftime(buffer, sizeof(buffer), _format.c_str(), &timeValue)) + return std::string(buffer) + "." + (millisRemainder < 1 ? "000" : millisRemainder < 10 ? "00" : millisRemainder < 100 ? "0" : "") + std::to_string(millisRemainder) + "Z"; + return std::string(); +} + +template +inline std::ostream& streamout(std::ostream& _out, std::vector const& _e) +{ + _out << "["; + if (!_e.empty()) + { + StreamOut::bypass(_out, _e.front()); + for (auto i = ++_e.begin(); i != _e.end(); ++i) + StreamOut::bypass(_out << ",", *i); + } + _out << "]"; + return _out; +} + +template inline std::ostream& operator<<(std::ostream& _out, std::vector const& _e) { streamout(_out, _e); return _out; } // Used in CommonJS.h + +template +inline std::ostream& streamout(std::ostream& _out, std::array const& _e) //used somewhere? +{ + _out << "["; + if (!_e.empty()) + { + StreamOut::bypass(_out, _e.front()); + auto i = _e.begin(); + for (++i; i != _e.end(); ++i) + StreamOut::bypass(_out << ",", *i); + } + _out << "]"; + return _out; +} +template inline std::ostream& operator<<(std::ostream& _out, std::array const& _e) { streamout(_out, _e); return _out; } + +template +std::ostream& streamout(std::ostream& _out, std::set const& _v) +{ + if (_v.empty()) + return _out << "{}"; + int i = 0; + for (auto p: _v) + _out << (!(i++) ? "{ " : ", ") << p; + return _out << " }"; +} +template inline std::ostream& operator<<(std::ostream& _out, std::set const& _e) { streamout(_out, _e); return _out; } + +template +std::ostream& streamout(std::ostream& _out, std::unordered_set const& _v) +{ + if (_v.empty()) + return _out << "{}"; + int i = 0; + for (auto p: _v) + _out << (!(i++) ? "{ " : ", ") << p; + return _out << " }"; +} +template inline std::ostream& operator<<(std::ostream& _out, std::unordered_set const& _e) { streamout(_out, _e); return _out; } + +// Functions that use streaming stuff. + +/// Converts arbitrary value to string representation using std::stringstream. +template +inline std::string toString(_T const& _t) +{ + std::ostringstream o; + o << _t; + return o.str(); +} + +template <> +inline std::string toString(std::string const& _s) +{ + return _s; +} + +template <> +inline std::string toString(uint8_t const& _u) +{ + std::ostringstream o; + o << static_cast(_u); + return o.str(); +} +} diff --git a/src/eth_client/libdevcore/DBFactory.cpp b/src/eth_client/libdevcore/DBFactory.cpp new file mode 100644 index 0000000000..0a01b7cde4 --- /dev/null +++ b/src/eth_client/libdevcore/DBFactory.cpp @@ -0,0 +1,147 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2018-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "DBFactory.h" +#include "FileSystem.h" +#include "LevelDB.h" +#include "libethcore/Exceptions.h" + + +namespace dev +{ +namespace db +{ +namespace fs = boost::filesystem; +namespace po = boost::program_options; + +auto g_kind = DatabaseKind::LevelDB; +fs::path g_dbPath; + +/// A helper type to build the table of DB implementations. +/// +/// More readable than std::tuple. +/// Fields are not initialized to allow usage of construction with initializer lists {}. +struct DBKindTableEntry +{ + DatabaseKind kind; + char const* name; +}; + +/// The table of available DB implementations. +/// +/// We don't use a map to avoid complex dynamic initialization. This list will never be long, +/// so linear search only to parse command line arguments is not a problem. +DBKindTableEntry dbKindsTable[] = { + {DatabaseKind::LevelDB, "leveldb"}, +}; + +void setDatabaseKindByName(std::string const& _name) +{ + for (auto& entry : dbKindsTable) + { + if (_name == entry.name) + { + g_kind = entry.kind; + return; + } + } + + BOOST_THROW_EXCEPTION( + eth::InvalidDatabaseKind() << errinfo_comment("invalid database name supplied: " + _name)); +} + +void setDatabaseKind(DatabaseKind _kind) +{ + g_kind = _kind; +} + +void setDatabasePath(std::string const& _path) +{ + g_dbPath = fs::path(_path); +} + +bool isDiskDatabase() +{ + switch (g_kind) + { + case DatabaseKind::LevelDB: + return true; + default: + return false; + } +} + +DatabaseKind databaseKind() +{ + return g_kind; +} + +fs::path databasePath() +{ + return g_dbPath.empty() ? getDataDir() : g_dbPath; +} + +po::options_description databaseProgramOptions(unsigned _lineLength) +{ + // It must be a static object because boost expects const char*. + static std::string const description = [] { + std::string names; + for (auto const& entry : dbKindsTable) + { + if (!names.empty()) + names += ", "; + names += entry.name; + } + + return "Select database implementation. Available options are: " + names + "."; + }(); + + po::options_description opts("DATABASE OPTIONS", _lineLength); + auto add = opts.add_options(); + + add("db", + po::value()->value_name("")->default_value("leveldb")->notifier( + setDatabaseKindByName), + description.data()); + + add("db-path", + po::value() + ->value_name("") + ->default_value(getDataDir().string()) + ->notifier(setDatabasePath), + "Database path (for non-memory database options)\n"); + + return opts; +} + +std::unique_ptr DBFactory::create() +{ + return create(databasePath()); +} + +std::unique_ptr DBFactory::create(fs::path const& _path) +{ + return create(g_kind, _path); +} + +std::unique_ptr DBFactory::create(DatabaseKind _kind) +{ + return create(_kind, databasePath()); +} + +std::unique_ptr DBFactory::create(DatabaseKind _kind, fs::path const& _path) +{ + switch (_kind) + { + case DatabaseKind::LevelDB: + return std::unique_ptr(new LevelDB(_path)); + break; + default: + assert(false); + return {}; + } +} + + +} // namespace db +} // namespace dev diff --git a/src/eth_client/libdevcore/DBFactory.h b/src/eth_client/libdevcore/DBFactory.h new file mode 100644 index 0000000000..d2cb2e62dd --- /dev/null +++ b/src/eth_client/libdevcore/DBFactory.h @@ -0,0 +1,50 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "Common.h" +#include "db.h" + +#include +#include + +namespace dev +{ +namespace db +{ +enum class DatabaseKind +{ + LevelDB +}; + +/// Provide a set of program options related to databases +/// +/// @param _lineLength The line length for description text wrapping, the same as in +/// boost::program_options::options_description::options_description(). +boost::program_options::options_description databaseProgramOptions( + unsigned _lineLength = boost::program_options::options_description::m_default_line_length); + +bool isDiskDatabase(); +DatabaseKind databaseKind(); +void setDatabaseKindByName(std::string const& _name); +void setDatabaseKind(DatabaseKind _kind); +boost::filesystem::path databasePath(); + +class DBFactory +{ +public: + DBFactory() = delete; + ~DBFactory() = delete; + + static std::unique_ptr create(); + static std::unique_ptr create(boost::filesystem::path const& _path); + static std::unique_ptr create(DatabaseKind _kind); + static std::unique_ptr create( + DatabaseKind _kind, boost::filesystem::path const& _path); + +private: +}; +} // namespace db +} // namespace dev diff --git a/src/eth_client/libdevcore/Exceptions.h b/src/eth_client/libdevcore/Exceptions.h new file mode 100644 index 0000000000..214eb93c7b --- /dev/null +++ b/src/eth_client/libdevcore/Exceptions.h @@ -0,0 +1,83 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "FixedHash.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dev +{ +/// Base class for all exceptions. +struct Exception : virtual std::exception, virtual boost::exception +{ + const char* what() const noexcept override { return boost::diagnostic_information_what(*this); } +}; + +#define DEV_SIMPLE_EXCEPTION(X) \ + struct X : virtual Exception \ + { \ + } + +/// Base class for all RLP exceptions. +struct RLPException : virtual Exception +{ +}; +#define DEV_SIMPLE_EXCEPTION_RLP(X) \ + struct X : virtual RLPException \ + { \ + } + +DEV_SIMPLE_EXCEPTION_RLP(BadCast); +DEV_SIMPLE_EXCEPTION_RLP(BadRLP); +DEV_SIMPLE_EXCEPTION_RLP(OversizeRLP); +DEV_SIMPLE_EXCEPTION_RLP(UndersizeRLP); + +DEV_SIMPLE_EXCEPTION(BadHexCharacter); +DEV_SIMPLE_EXCEPTION(NoNetworking); +DEV_SIMPLE_EXCEPTION(NoUPnPDevice); +DEV_SIMPLE_EXCEPTION(RootNotFound); +DEV_SIMPLE_EXCEPTION(BadRoot); +DEV_SIMPLE_EXCEPTION(FileError); +DEV_SIMPLE_EXCEPTION(Overflow); +DEV_SIMPLE_EXCEPTION(FailedInvariant); +DEV_SIMPLE_EXCEPTION(ValueTooLarge); +DEV_SIMPLE_EXCEPTION(UnknownField); +DEV_SIMPLE_EXCEPTION(MissingField); +DEV_SIMPLE_EXCEPTION(SyntaxError); +DEV_SIMPLE_EXCEPTION(WrongFieldType); +DEV_SIMPLE_EXCEPTION(InterfaceNotSupported); +DEV_SIMPLE_EXCEPTION(ExternalFunctionFailure); +DEV_SIMPLE_EXCEPTION(WaitTimeout); + +// error information to be added to exceptions +using errinfo_invalidSymbol = boost::error_info; +using errinfo_wrongAddress = boost::error_info; +using errinfo_comment = boost::error_info; +using errinfo_required = boost::error_info; +using errinfo_got = boost::error_info; +using errinfo_min = boost::error_info; +using errinfo_max = boost::error_info; +using RequirementError = boost::tuple; +using RequirementErrorComment = boost::tuple; +using errinfo_hash256 = boost::error_info; +using errinfo_required_h256 = boost::error_info; +using errinfo_got_h256 = boost::error_info; +using Hash256RequirementError = boost::tuple; +using errinfo_extraData = boost::error_info; +using errinfo_externalFunction = boost::errinfo_api_function; +using errinfo_interface = boost::error_info; +using errinfo_path = boost::error_info; +using errinfo_nodeID = boost::error_info; +using errinfo_nestedException = boost::errinfo_nested_exception; +} diff --git a/src/eth_client/libdevcore/FileSystem.cpp b/src/eth_client/libdevcore/FileSystem.cpp new file mode 100644 index 0000000000..8d15e9e210 --- /dev/null +++ b/src/eth_client/libdevcore/FileSystem.cpp @@ -0,0 +1,98 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include "FileSystem.h" +#include "Common.h" +#include "Log.h" + +#if defined(_WIN32) +#include +#else +#include +#include +#include +#include +#endif +#include +using namespace std; +using namespace dev; + +namespace fs = boost::filesystem; + +// Should be written to only once during startup +static fs::path s_ethereumDatadir; +static fs::path s_ethereumIpcPath; + +void dev::setDataDir(fs::path const& _dataDir) +{ + s_ethereumDatadir = _dataDir; +} + +void dev::setIpcPath(fs::path const& _ipcDir) +{ + s_ethereumIpcPath = _ipcDir; +} + +fs::path dev::getIpcPath() +{ + // Strip "geth.ipc" suffix if provided. + if (s_ethereumIpcPath.filename() == "geth.ipc") + return s_ethereumIpcPath.parent_path(); + else + return s_ethereumIpcPath; +} + +fs::path dev::getDataDir(string _prefix) +{ + if (_prefix.empty()) + _prefix = "ethereum"; + if (_prefix == "ethereum" && !s_ethereumDatadir.empty()) + return s_ethereumDatadir; + return getDefaultDataDir(_prefix); +} + +fs::path dev::getDefaultDataDir(string _prefix) +{ + if (_prefix.empty()) + _prefix = "ethereum"; + +#if defined(_WIN32) + _prefix[0] = toupper(_prefix[0]); + char path[1024] = ""; + if (SHGetSpecialFolderPathA(NULL, path, CSIDL_APPDATA, true)) + return fs::path(path) / _prefix; + else + { + #ifndef _MSC_VER // todo? + cwarn << "getDataDir(): SHGetSpecialFolderPathA() failed."; + #endif + BOOST_THROW_EXCEPTION(std::runtime_error("getDataDir() - SHGetSpecialFolderPathA() failed.")); + } +#else + fs::path dataDirPath; + char const* homeDir = getenv("HOME"); + if (!homeDir || strlen(homeDir) == 0) + { + struct passwd* pwd = getpwuid(getuid()); + if (pwd) + homeDir = pwd->pw_dir; + } + + if (!homeDir || strlen(homeDir) == 0) + dataDirPath = fs::path("/"); + else + dataDirPath = fs::path(homeDir); + + return dataDirPath / ("." + _prefix); +#endif +} + +fs::path dev::appendToFilename(fs::path const& _orig, string const& _suffix) +{ + if (_orig.filename() == fs::path(".") || _orig.filename() == fs::path("..")) + return _orig / fs::path(_suffix); + else + return _orig.parent_path() / fs::path( _orig.filename().string() + _suffix); +} diff --git a/src/eth_client/libdevcore/FileSystem.h b/src/eth_client/libdevcore/FileSystem.h new file mode 100644 index 0000000000..a09609fd5c --- /dev/null +++ b/src/eth_client/libdevcore/FileSystem.h @@ -0,0 +1,27 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include + +namespace dev +{ + +/// Sets the data dir for the default ("ethereum") prefix. +void setDataDir(boost::filesystem::path const& _dir); +/// @returns the path for user data. +boost::filesystem::path getDataDir(std::string _prefix = "ethereum"); +/// @returns the default path for user data, ignoring the one set by `setDataDir`. +boost::filesystem::path getDefaultDataDir(std::string _prefix = "ethereum"); +/// Sets the ipc socket dir +void setIpcPath(boost::filesystem::path const& _ipcPath); +/// @returns the ipc path (default is DataDir) +boost::filesystem::path getIpcPath(); + +/// @returns a new path whose file name is suffixed with the given suffix. +boost::filesystem::path appendToFilename(boost::filesystem::path const& _orig, std::string const& _suffix); + +} diff --git a/src/eth_client/libdevcore/FixedHash.cpp b/src/eth_client/libdevcore/FixedHash.cpp new file mode 100644 index 0000000000..6b8e44268c --- /dev/null +++ b/src/eth_client/libdevcore/FixedHash.cpp @@ -0,0 +1,35 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "FixedHash.h" +#include + +namespace dev +{ + +std::random_device s_fixedHashEngine; + +h128 fromUUID(std::string const& _uuid) +{ + try + { + return h128(boost::replace_all_copy(_uuid, "-", "")); + } + catch (...) + { + return h128(); + } +} + +std::string toUUID(h128 const& _uuid) +{ + std::string ret = toHex(_uuid.ref()); + for (unsigned i: {20, 16, 12, 8}) + ret.insert(ret.begin() + i, '-'); + return ret; +} + +} + + + diff --git a/src/eth_client/libdevcore/FixedHash.h b/src/eth_client/libdevcore/FixedHash.h new file mode 100644 index 0000000000..996ac311d4 --- /dev/null +++ b/src/eth_client/libdevcore/FixedHash.h @@ -0,0 +1,382 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// The FixedHash fixed-size "hash" container type. +#pragma once + +#include +#include +#include +#include +#include +#include "CommonData.h" + +namespace dev +{ + +/// Compile-time calculation of Log2 of constant values. +template struct StaticLog2 { enum { result = 1 + StaticLog2::result }; }; +template <> struct StaticLog2<1> { enum { result = 0 }; }; + +extern std::random_device s_fixedHashEngine; + +/// 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 +class FixedHash +{ +public: + /// The corresponding arithmetic type. + using Arith = boost::multiprecision::number>; + + /// 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 }; + + /// Method to convert from a string. + enum ConstructFromHashType { AlignLeft, AlignRight, FailIfDifferent }; + + /// Construct an empty hash. + FixedHash() { m_data.fill(0); } + + /// Construct from another hash, filling with zeroes or cropping as necessary. + template explicit FixedHash(FixedHash const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; } + + /// Convert from the corresponding arithmetic type. + FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); } + + /// Convert from unsigned + explicit FixedHash(unsigned _u) { toBigEndian(_u, m_data); } + + /// Explicitly construct, copying from a byte array. + explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } } + + /// Explicitly construct, copying from a byte array. + explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } } + + /// 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, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : dev::asBytes(_s), _ht) {} + + /// Convert to arithmetic type. + operator Arith() const { return fromBigEndian(m_data); } + + /// @returns true iff this is the empty hash. + explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](byte _b) { return _b != 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 { for (unsigned i = 0; i < N; ++i) if (m_data[i] < _c.m_data[i]) return true; else if (m_data[i] > _c.m_data[i]) return false; return false; } + bool operator>=(FixedHash const& _c) const { return !operator<(_c); } + bool operator<=(FixedHash const& _c) const { return operator==(_c) || operator<(_c); } + bool operator>(FixedHash const& _c) const { return !operator<=(_c); } + + // The obvious binary operators. + FixedHash& operator^=(FixedHash const& _c) { for (unsigned 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 (unsigned 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 (unsigned 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~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; } + + // Big-endian increment. + FixedHash& operator++() { for (unsigned i = size; i > 0 && !++m_data[--i]; ) {} return *this; } + + /// @returns true if all one-bits in @a _c are set in this object. + bool contains(FixedHash const& _c) const { return (*this & _c) == _c; } + + /// @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)) + "\342\200\246"; } + + /// @returns a version of the hash as a user-readable hex string that leaves out the middle part. + std::string abridgedMiddle() const { return toHex(ref().cropped(0, 4)) + "\342\200\246" + toHex(ref().cropped(N - 4)); } + + /// @returns the hash as a user-readable hex string. + std::string hex() const { return toHex(ref()); } + + /// @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 begin iterator. + auto begin() const -> typename std::array::const_iterator { return m_data.begin(); } + + /// @returns end iterator. + auto end() const -> typename std::array::const_iterator { return m_data.end(); } + + /// @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& asArray() { return m_data; } + + /// @returns a constant reference to the object's data as an STL array. + std::array const& asArray() const { return m_data; } + + /// Populate with random data. + template + void randomize(Engine& _eng) + { + for (auto& i: m_data) + i = (uint8_t)std::uniform_int_distribution(0, 255)(_eng); + } + + /// @returns a random valued object. + static FixedHash random() { FixedHash ret; ret.randomize(s_fixedHashEngine); return ret; } + + struct hash + { + /// Make a hash of the object's data. + size_t operator()(FixedHash const& _value) const { return boost::hash_range(_value.m_data.cbegin(), _value.m_data.cend()); } + }; + + template inline FixedHash& shiftBloom(FixedHash const& _h) + { + return (*this |= _h.template bloomPart()); + } + + template inline bool containsBloom(FixedHash const& _h) + { + return contains(_h.template bloomPart()); + } + + template inline FixedHash bloomPart() const + { + unsigned const c_bloomBits = M * 8; + unsigned const c_mask = c_bloomBits - 1; + unsigned const c_bloomBytes = (StaticLog2::result + 7) / 8; + + static_assert((M & (M - 1)) == 0, "M must be power-of-two"); + static_assert(P * c_bloomBytes <= N, "out of range"); + + FixedHash ret; + byte const* p = data(); + for (unsigned i = 0; i < P; ++i) + { + unsigned index = 0; + for (unsigned j = 0; j < c_bloomBytes; ++j, ++p) + index = (index << 8) | *p; + index &= c_mask; + ret[M - 1 - index / 8] |= (1 << (index % 8)); + } + return ret; + } + + /// Returns the index of the first bit set to one, or size() * 8 if no bits are set. + inline unsigned firstBitSet() const + { + unsigned ret = 0; + for (auto d: m_data) + if (d) + { + for (;; ++ret, d <<= 1) + { + if (d & 0x80) + return ret; + } + } + else + ret += 8; + return ret; + } + + void clear() { m_data.fill(0); } + +private: + std::array m_data; ///< The binary data. +}; + +template +class SecureFixedHash: private FixedHash +{ +public: + using ConstructFromHashType = typename FixedHash::ConstructFromHashType; + using ConstructFromStringType = typename FixedHash::ConstructFromStringType; + using ConstructFromPointerType = typename FixedHash::ConstructFromPointerType; + SecureFixedHash() = default; + SecureFixedHash(SecureFixedHash const&) = default; + explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b, _t) {} + explicit SecureFixedHash(bytesConstRef _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b, _t) {} + explicit SecureFixedHash(bytesSec const& _b, ConstructFromHashType _t = FixedHash::FailIfDifferent): FixedHash(_b.ref(), _t) {} + template explicit SecureFixedHash(FixedHash const& _h, ConstructFromHashType _t = FixedHash::AlignLeft): FixedHash(_h, _t) {} + template explicit SecureFixedHash(SecureFixedHash const& _h, ConstructFromHashType _t = FixedHash::AlignLeft): FixedHash(_h.makeInsecure(), _t) {} + explicit SecureFixedHash(std::string const& _s, ConstructFromStringType _t = FixedHash::FromHex, ConstructFromHashType _ht = FixedHash::FailIfDifferent): FixedHash(_s, _t, _ht) {} + explicit SecureFixedHash(byte const* _d, ConstructFromPointerType _t): FixedHash(_d, _t) {} + ~SecureFixedHash() { ref().cleanse(); } + + SecureFixedHash& operator=(SecureFixedHash const& _c) + { + if (&_c == this) + return *this; + ref().cleanse(); + FixedHash::operator=(static_cast const&>(_c)); + return *this; + } + + using FixedHash::size; + + bytesSec asBytesSec() const { return bytesSec(ref()); } + + FixedHash const& makeInsecure() const { return static_cast const&>(*this); } + FixedHash& writable() { clear(); return static_cast&>(*this); } + + using FixedHash::operator bool; + + // The obvious comparison operators. + bool operator==(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator==(static_cast const&>(_c)); } + bool operator!=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator!=(static_cast const&>(_c)); } + bool operator<(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator<(static_cast const&>(_c)); } + bool operator>=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator>=(static_cast const&>(_c)); } + bool operator<=(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator<=(static_cast const&>(_c)); } + bool operator>(SecureFixedHash const& _c) const { return static_cast const&>(*this).operator>(static_cast const&>(_c)); } + + using FixedHash::operator==; + using FixedHash::operator!=; + using FixedHash::operator<; + using FixedHash::operator>=; + using FixedHash::operator<=; + using FixedHash::operator>; + + // The obvious binary operators. + SecureFixedHash& operator^=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator^(FixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator|(FixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(FixedHash const& _c) { static_cast&>(*this).operator^=(_c); return *this; } + SecureFixedHash operator&(FixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + + SecureFixedHash& operator^=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator^(SecureFixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; } + SecureFixedHash& operator|=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator|(SecureFixedHash const& _c) const { return SecureFixedHash(*this) |= _c; } + SecureFixedHash& operator&=(SecureFixedHash const& _c) { static_cast&>(*this).operator^=(static_cast const&>(_c)); return *this; } + SecureFixedHash operator&(SecureFixedHash const& _c) const { return SecureFixedHash(*this) &= _c; } + SecureFixedHash operator~() const { auto r = ~static_cast const&>(*this); return static_cast(r); } + + using FixedHash::abridged; + using FixedHash::abridgedMiddle; + + bytesConstRef ref() const { return FixedHash::ref(); } + byte const* data() const { return FixedHash::data(); } + + static SecureFixedHash random() { SecureFixedHash ret; ret.randomize(s_fixedHashEngine); return ret; } + using FixedHash::firstBitSet; + + void clear() { ref().cleanse(); } +}; + +/// Fast equality operator for h256. +template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const +{ + const uint64_t* hash1 = (const uint64_t*)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 +{ + uint64_t const* data = reinterpret_cast(value.data()); + return boost::hash_range(data, data + 4); +} + +/// Stream I/O for the FixedHash class. +template +inline std::ostream& operator<<(std::ostream& _out, FixedHash const& _h) +{ + _out << toHex(_h); + return _out; +} + +template +inline std::istream& operator>>(std::istream& _in, FixedHash& o_h) +{ + std::string s; + _in >> s; + o_h = FixedHash(s, FixedHash::FromHex, FixedHash::AlignRight); + return _in; +} + +/// Stream I/O for the SecureFixedHash class. +template +inline std::ostream& operator<<(std::ostream& _out, SecureFixedHash const& _h) +{ + _out << "SecureFixedHash#" << std::hex << typename FixedHash::hash()(_h.makeInsecure()) << std::dec; + return _out; +} + +// Common types of FixedHash. +using h2048 = FixedHash<256>; +using h1024 = FixedHash<128>; +using h520 = FixedHash<65>; +using h512 = FixedHash<64>; +using h256 = FixedHash<32>; +using h160 = FixedHash<20>; +using h128 = FixedHash<16>; +using h64 = FixedHash<8>; +using h512s = std::vector; +using h256s = std::vector; +using h160s = std::vector; +using h256Set = std::set; +using h160Set = std::set; +using h256Hash = std::unordered_set; +using h160Hash = std::unordered_set; + +/// 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; +} + +h128 fromUUID(std::string const& _uuid); + +std::string toUUID(h128 const& _uuid); + +inline std::string toString(h256s const& _bs) +{ + std::ostringstream out; + out << "[ "; + for (h256 const& i: _bs) + out << i.abridged() << ", "; + out << "]"; + return out.str(); +} + +} + +namespace std +{ + /// Forward std::hash to dev::FixedHash::hash. + template<> struct hash: dev::h64::hash {}; + template<> struct hash: dev::h128::hash {}; + template<> struct hash: dev::h160::hash {}; + template<> struct hash: dev::h256::hash {}; + template<> struct hash: dev::h512::hash {}; +} diff --git a/src/eth_client/libdevcore/Guards.h b/src/eth_client/libdevcore/Guards.h new file mode 100644 index 0000000000..001de9885c --- /dev/null +++ b/src/eth_client/libdevcore/Guards.h @@ -0,0 +1,130 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include +#include +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#pragma warning(pop) +#pragma GCC diagnostic pop + +namespace dev +{ + +using Mutex = std::mutex; +using RecursiveMutex = std::recursive_mutex; +using SharedMutex = boost::shared_mutex; + +using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; +using RecursiveGuard = std::lock_guard; +using ReadGuard = boost::shared_lock; +using UpgradableGuard = boost::upgrade_lock; +using UpgradeGuard = boost::upgrade_to_unique_lock; +using WriteGuard = boost::unique_lock; + +template +struct GenericGuardBool: GuardType +{ + GenericGuardBool(MutexType& _m): GuardType(_m) {} + bool b = true; +}; +template +struct GenericUnguardBool +{ + GenericUnguardBool(MutexType& _m): m(_m) { m.unlock(); } + ~GenericUnguardBool() { m.lock(); } + bool b = true; + MutexType& m; +}; +template +struct GenericUnguardSharedBool +{ + GenericUnguardSharedBool(MutexType& _m): m(_m) { m.unlock_shared(); } + ~GenericUnguardSharedBool() { m.lock_shared(); } + bool b = true; + MutexType& m; +}; + +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + +/** @brief Simple block guard. + * The expression/block following is guarded though the given mutex. + * Usage: + * @code + * Mutex m; + * unsigned d; + * ... + * ETH_(m) d = 1; + * ... + * ETH_(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; } + * @endcode + * + * There are several variants of this basic mechanism for different Mutex types and Guards. + * + * There is also the UNGUARD variant which allows an unguarded expression/block to exist within a + * guarded expression. eg: + * + * @code + * Mutex m; + * int d; + * ... + * ETH_GUARDED(m) + * { + * for (auto d = 50; d > 25; --d) + * foo(d); + * ETH_UNGUARDED(m) + * bar(); + * for (; d > 0; --d) + * foo(d); + * } + * @endcode + */ + +#define DEV_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_READ_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_WRITE_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_RECURSIVE_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_UNGUARDED(MUTEX) \ + for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_READ_UNGUARDED(MUTEX) \ + for (GenericUnguardSharedBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define DEV_WRITE_UNGUARDED(MUTEX) \ + for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) + +} diff --git a/src/eth_client/libdevcore/JsonUtils.cpp b/src/eth_client/libdevcore/JsonUtils.cpp new file mode 100644 index 0000000000..ecdc8405e9 --- /dev/null +++ b/src/eth_client/libdevcore/JsonUtils.cpp @@ -0,0 +1,100 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include +#include +#include +#include +#include +#include + +void dev::validateFieldNames(json_spirit::mObject const& _obj, std::set const& _allowedFields) +{ + for (auto const& elm: _obj) + if (_allowedFields.find(elm.first) == _allowedFields.end()) + { + std::string const comment = "Unknown field in config: " + elm.first; + std::cerr << comment << "\n"; + BOOST_THROW_EXCEPTION(UnknownField() << errinfo_comment(comment)); + } +} + +std::string dev::jsonTypeAsString(json_spirit::Value_type _type) +{ + switch (_type) + { + case json_spirit::obj_type: + return "json Object"; + case json_spirit::array_type: + return "json Array"; + case json_spirit::str_type: + return "json String"; + case json_spirit::bool_type: + return "json Bool"; + case json_spirit::int_type: + return "json Int"; + case json_spirit::real_type: + return "json Real"; + case json_spirit::null_type: + return "json Null"; + default: + return "json n/a"; + } +} + +void dev::requireJsonFields(json_spirit::mObject const& _o, std::string const& _config, + std::map const& _validationMap) +{ + // check for unexpected fiedls + for (auto const& field : _o) + { + if (!_validationMap.count(field.first)) + { + std::string const comment = + "Unexpected field '" + field.first + "' in config: " + _config; + std::cerr << comment << "\n" + << json_spirit::write_string((json_spirit::mValue)_o, true) << "\n"; + BOOST_THROW_EXCEPTION(UnknownField() << errinfo_comment(comment)); + } + } + + // check field types with validation map + for (auto const vmap : _validationMap) + { + auto const& expectedFieldName = vmap.first; + auto const& expectedFieldPresence = vmap.second.second; + // check that all required fields are in the object + if (!_o.count(expectedFieldName)) + { + if (expectedFieldPresence == JsonFieldPresence::Required) + { + std::string const comment = + "Expected field '" + expectedFieldName + "' not found in config: " + _config; + std::cerr << comment << "\n" + << json_spirit::write_string((json_spirit::mValue)_o, true) << "\n"; + BOOST_THROW_EXCEPTION(MissingField() << errinfo_comment(comment)); + } + else if (expectedFieldPresence == JsonFieldPresence::Optional) + continue; + } + + // check that field type is one of allowed field types + auto const& expectedFieldTypes = vmap.second.first; + bool matched = expectedFieldTypes.count(_o.at(expectedFieldName).type()); + if (matched == false) + { + std::vector types; + for (auto const& type : expectedFieldTypes) + types.push_back(jsonTypeAsString(type)); + std::string sTypes = boost::algorithm::join(types, " or "); + + std::string const comment = "Field '" + expectedFieldName + "' is expected to be " + + sTypes + ", but is set to " + + jsonTypeAsString(_o.at(expectedFieldName).type()) + " in " + + _config; + std::cerr << comment << "\n" + << json_spirit::write_string((json_spirit::mValue)_o, true) << "\n"; + BOOST_THROW_EXCEPTION(WrongFieldType() << errinfo_comment(comment)); + } + } +} diff --git a/src/eth_client/libdevcore/JsonUtils.h b/src/eth_client/libdevcore/JsonUtils.h new file mode 100644 index 0000000000..635cb7ba33 --- /dev/null +++ b/src/eth_client/libdevcore/JsonUtils.h @@ -0,0 +1,37 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include +#include +#include + +namespace dev +{ +// Throws UnknownField() if _obj contains field names not listed in _allowedFields. +void validateFieldNames(json_spirit::mObject const& _obj, std::set const& _allowedFields); + +// Converts json value type to string +std::string jsonTypeAsString(json_spirit::Value_type _type); + +enum class JsonFieldPresence +{ + Required, + Optional +}; +using JsonTypeSet = std::set; +using JsonFieldOptions = std::pair; +/// Check the json object with validation map that reuires certain field of certain type to be +/// present in json +/** + @param _o a json object to check + @param _configName a string with json object name. Will apper in error message. + @param _validationMap a map with json objects that would be checked. "objName" -> {js::str_type, + jsonField::Required} +*/ +void requireJsonFields(json_spirit::mObject const& _o, std::string const& _configName, + std::map const& _validationMap); +} diff --git a/src/eth_client/libdevcore/LevelDB.cpp b/src/eth_client/libdevcore/LevelDB.cpp new file mode 100644 index 0000000000..536086903e --- /dev/null +++ b/src/eth_client/libdevcore/LevelDB.cpp @@ -0,0 +1,180 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2017-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "LevelDB.h" +#include "Assertions.h" + +namespace dev +{ +namespace db +{ +namespace +{ +inline leveldb::Slice toLDBSlice(Slice _slice) +{ + return leveldb::Slice(_slice.data(), _slice.size()); +} + +DatabaseStatus toDatabaseStatus(leveldb::Status const& _status) +{ + if (_status.ok()) + return DatabaseStatus::Ok; + else if (_status.IsIOError()) + return DatabaseStatus::IOError; + else if (_status.IsCorruption()) + return DatabaseStatus::Corruption; + else if (_status.IsNotFound()) + return DatabaseStatus::NotFound; + else + return DatabaseStatus::Unknown; +} + +void checkStatus(leveldb::Status const& _status, boost::filesystem::path const& _path = {}) +{ + if (_status.ok()) + return; + + DatabaseError ex; + ex << errinfo_dbStatusCode(toDatabaseStatus(_status)) + << errinfo_dbStatusString(_status.ToString()); + if (!_path.empty()) + ex << errinfo_path(_path.string()); + + BOOST_THROW_EXCEPTION(ex); +} + +class LevelDBWriteBatch : public WriteBatchFace +{ +public: + void insert(Slice _key, Slice _value) override; + void kill(Slice _key) override; + + leveldb::WriteBatch const& writeBatch() const { return m_writeBatch; } + leveldb::WriteBatch& writeBatch() { return m_writeBatch; } + +private: + leveldb::WriteBatch m_writeBatch; +}; + +void LevelDBWriteBatch::insert(Slice _key, Slice _value) +{ + m_writeBatch.Put(toLDBSlice(_key), toLDBSlice(_value)); +} + +void LevelDBWriteBatch::kill(Slice _key) +{ + m_writeBatch.Delete(toLDBSlice(_key)); +} + +} // namespace + +leveldb::ReadOptions LevelDB::defaultReadOptions() +{ + return leveldb::ReadOptions(); +} + +leveldb::WriteOptions LevelDB::defaultWriteOptions() +{ + return leveldb::WriteOptions(); +} + +leveldb::Options LevelDB::defaultDBOptions() +{ + leveldb::Options options; + options.create_if_missing = true; + options.max_open_files = 256; + return options; +} + +LevelDB::LevelDB(boost::filesystem::path const& _path, leveldb::ReadOptions _readOptions, + leveldb::WriteOptions _writeOptions, leveldb::Options _dbOptions) + : m_db(nullptr), m_readOptions(std::move(_readOptions)), m_writeOptions(std::move(_writeOptions)) +{ + auto db = static_cast(nullptr); + auto const status = leveldb::DB::Open(_dbOptions, _path.string(), &db); + checkStatus(status, _path); + + assert(db); + m_db.reset(db); +} + +std::string LevelDB::lookup(Slice _key) const +{ + leveldb::Slice const key(_key.data(), _key.size()); + std::string value; + auto const status = m_db->Get(m_readOptions, key, &value); + if (status.IsNotFound()) + return std::string(); + + checkStatus(status); + return value; +} + +bool LevelDB::exists(Slice _key) const +{ + std::string value; + leveldb::Slice const key(_key.data(), _key.size()); + auto const status = m_db->Get(m_readOptions, key, &value); + if (status.IsNotFound()) + return false; + + checkStatus(status); + return true; +} + +void LevelDB::insert(Slice _key, Slice _value) +{ + leveldb::Slice const key(_key.data(), _key.size()); + leveldb::Slice const value(_value.data(), _value.size()); + auto const status = m_db->Put(m_writeOptions, key, value); + checkStatus(status); +} + +void LevelDB::kill(Slice _key) +{ + leveldb::Slice const key(_key.data(), _key.size()); + auto const status = m_db->Delete(m_writeOptions, key); + checkStatus(status); +} + +std::unique_ptr LevelDB::createWriteBatch() const +{ + return std::unique_ptr(new LevelDBWriteBatch()); +} + +void LevelDB::commit(std::unique_ptr _batch) +{ + if (!_batch) + { + BOOST_THROW_EXCEPTION(DatabaseError() << errinfo_comment("Cannot commit null batch")); + } + auto* batchPtr = dynamic_cast(_batch.get()); + if (!batchPtr) + { + BOOST_THROW_EXCEPTION( + DatabaseError() << errinfo_comment("Invalid batch type passed to LevelDB::commit")); + } + auto const status = m_db->Write(m_writeOptions, &batchPtr->writeBatch()); + checkStatus(status); +} + +void LevelDB::forEach(std::function _f) const +{ + std::unique_ptr itr(m_db->NewIterator(m_readOptions)); + if (itr == nullptr) + { + BOOST_THROW_EXCEPTION(DatabaseError() << errinfo_comment("null iterator")); + } + auto keepIterating = true; + for (itr->SeekToFirst(); keepIterating && itr->Valid(); itr->Next()) + { + auto const dbKey = itr->key(); + auto const dbValue = itr->value(); + Slice const key(dbKey.data(), dbKey.size()); + Slice const value(dbValue.data(), dbValue.size()); + keepIterating = _f(key, value); + } +} + +} // namespace db +} // namespace dev diff --git a/src/eth_client/libdevcore/LevelDB.h b/src/eth_client/libdevcore/LevelDB.h new file mode 100644 index 0000000000..37da58fbb0 --- /dev/null +++ b/src/eth_client/libdevcore/LevelDB.h @@ -0,0 +1,46 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2017-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "db.h" + +#include +#include +#include + +namespace dev +{ +namespace db +{ +class LevelDB : public DatabaseFace +{ +public: + static leveldb::ReadOptions defaultReadOptions(); + static leveldb::WriteOptions defaultWriteOptions(); + static leveldb::Options defaultDBOptions(); + + explicit LevelDB(boost::filesystem::path const& _path, + leveldb::ReadOptions _readOptions = defaultReadOptions(), + leveldb::WriteOptions _writeOptions = defaultWriteOptions(), + leveldb::Options _dbOptions = defaultDBOptions()); + + std::string lookup(Slice _key) const override; + bool exists(Slice _key) const override; + void insert(Slice _key, Slice _value) override; + void kill(Slice _key) override; + + std::unique_ptr createWriteBatch() const override; + void commit(std::unique_ptr _batch) override; + + void forEach(std::function _f) const override; + +private: + std::unique_ptr m_db; + leveldb::ReadOptions const m_readOptions; + leveldb::WriteOptions const m_writeOptions; +}; + +} // namespace db +} // namespace dev diff --git a/src/eth_client/libdevcore/Log.cpp b/src/eth_client/libdevcore/Log.cpp new file mode 100644 index 0000000000..29164b4baa --- /dev/null +++ b/src/eth_client/libdevcore/Log.cpp @@ -0,0 +1,41 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "Log.h" + +#ifdef __APPLE__ +#include +#endif + +namespace dev +{ + +int g_logVerbosity = 5; +Logger g_errorLogger(VerbosityError, "error"); +Logger g_warnLogger(VerbosityWarning, "warn"); +Logger g_noteLogger(VerbosityInfo, "info"); +Logger g_debugLogger(VerbosityDebug, "debug"); +Logger g_traceLogger(VerbosityTrace, "trace"); + +void setThreadName(std::string const&) +{} + +std::string getThreadName() +{ + return ""; +} + +void simpleDebugOut(std::string const& _s, char const*) +{ + std::cerr << _s << std::endl << std::flush; +} + +std::function g_logPost = simpleDebugOut; + +bool isVmTraceEnabled() +{ + return VerbosityTrace < g_logVerbosity; +} + +} // namespace + diff --git a/src/eth_client/libdevcore/Log.h b/src/eth_client/libdevcore/Log.h new file mode 100644 index 0000000000..e78bd6d29a --- /dev/null +++ b/src/eth_client/libdevcore/Log.h @@ -0,0 +1,226 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "CommonIO.h" +#include "FixedHash.h" +#include +#include + +namespace dev +{ +/// For better formatting it is recommended to limit thread name to max 4 characters. +void setThreadName(std::string const& _n); + +/// Set the current thread's log name. +std::string getThreadName(); + +enum class LogTag +{ + None, + Url, + Error, + Special +}; + +class LogOutputStreamBase +{ +public: + LogOutputStreamBase(char const* _id, unsigned _v, bool _autospacing): + m_autospacing(_autospacing), + m_verbosity(_v), + m_id(_id) + {} + + void comment(std::string const& _t) + { + m_sstr << _t; + m_logTag = LogTag::None; + } + + void append(unsigned long _t) { m_sstr << _t; } + void append(long _t) { m_sstr << _t; } + void append(unsigned int _t) { m_sstr << _t; } + void append(int _t) { m_sstr << _t; } + void append(bigint const& _t) { m_sstr << _t; } + void append(u256 const& _t) { m_sstr << _t; } + void append(u160 const& _t) { m_sstr << _t; } + void append(double _t) { m_sstr << _t; } + template void append(FixedHash const& _t) { m_sstr << "#" << _t.abridged(); } + void append(h160 const& _t) { m_sstr << "@" << _t.abridged(); } + void append(h256 const& _t) { m_sstr << "#" << _t.abridged(); } + void append(h512 const& _t) { m_sstr << "##" << _t.abridged(); } + void append(std::string const& _t) { m_sstr << "\"" + _t + "\""; } + void append(bytes const& _t) { m_sstr << "%" << toHex(_t); } + void append(bytesConstRef _t) { m_sstr << "%" << toHex(_t); } + template void append(std::vector const& _t) + { + m_sstr << "["; + int n = 0; + for (auto const& i: _t) + { + m_sstr << (n++ ? ", " : ""); + append(i); + } + m_sstr << "]"; + } + template void append(std::set const& _t) + { + m_sstr << "{"; + int n = 0; + for (auto const& i: _t) + { + m_sstr << (n++ ? ", " : ""); + append(i); + } + m_sstr << "}"; + } + template void append(std::map const& _t) + { + m_sstr << "{"; + int n = 0; + for (auto const& i: _t) + { + m_sstr << (n++ ? ", " : ""); + append(i.first); + m_sstr << (n++ ? ": " : ""); + append(i.second); + } + m_sstr << "}"; + } + template void append(std::unordered_set const& _t) + { + m_sstr << "{"; + int n = 0; + for (auto const& i: _t) + { + m_sstr << (n++ ? ", " : ""); + append(i); + } + m_sstr << "}"; + } + template void append(std::unordered_map const& _t) + { + m_sstr << "{"; + int n = 0; + for (auto const& i: _t) + { + m_sstr << (n++ ? ", " : ""); + append(i.first); + m_sstr << (n++ ? ": " : ""); + append(i.second); + } + m_sstr << "}"; + } + template void append(std::pair const& _t) + { + m_sstr << "("; + append(_t.first); + m_sstr << ", "; + append(_t.second); + m_sstr << ")"; + } + template void append(T const& _t) + { + m_sstr << toString(_t); + } + +protected: + bool m_autospacing = false; + unsigned m_verbosity = 0; + char const* m_id; + std::stringstream m_sstr; ///< The accrued log entry. + LogTag m_logTag = LogTag::None; +}; + +class Logger +{ +public: + Logger(int _verbosity, std::string _channel): + verbosity(_verbosity), + channel(_channel) + {} + + const char* name(){return channel.c_str();} + + int verbosity; + std::string channel; +}; + +/// 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 g_logPost; + +/// Is vm trace enabled +bool isVmTraceEnabled(); + +/// Logging class, iostream-like, that can be shifted to. +class LogOutputStream: LogOutputStreamBase +{ +public: + /// Construct a new object. + LogOutputStream(Logger _Id): + LogOutputStreamBase(_Id.name(), _Id.verbosity, true), + Id(_Id), + _AutoSpacing(true) + {} + + /// Destructor. Posts the accrued log entry to the g_logPost function. + ~LogOutputStream() { if (Id.verbosity <= g_logVerbosity) g_logPost(m_sstr.str(), Id.name()); } + + LogOutputStream& operator<<(std::string const& _t) { if (Id.verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; comment(_t); } return *this; } + + LogOutputStream& operator<<(LogTag _t) { m_logTag = _t; return *this; } + + /// Shift arbitrary data to the log. Spaces will be added between items as required. + template LogOutputStream& operator<<(T const& _t){ if (Id.verbosity <= g_logVerbosity) { if (_AutoSpacing && m_sstr.str().size() && m_sstr.str().back() != ' ') m_sstr << " "; append(_t); } return *this; } +private: + Logger Id; + bool _AutoSpacing; +}; + +#define LOG_STREAM(SEVERITY, CHANNEL) dev::LogOutputStream(Logger(SEVERITY, CHANNEL)) +#define LOG(LOGGER) dev::LogOutputStream(LOGGER) + +enum Verbosity +{ + VerbositySilent = -1, + VerbosityError = 0, + VerbosityWarning = 1, + VerbosityInfo = 2, + VerbosityDebug = 3, + VerbosityTrace = 4, +}; + +// Simple macro to log to any channel a message without creating a logger object +// e.g. clog(VerbosityInfo, "channel") << "message"; +#define clog(SEVERITY, CHANNEL) LOG(Logger(SEVERITY, CHANNEL)) + +// Simple cout-like stream objects for accessing common log channels. +extern Logger g_errorLogger; +extern Logger g_warnLogger; +extern Logger g_noteLogger; +extern Logger g_debugLogger; +extern Logger g_traceLogger; + +#define cerror LOG(dev::g_errorLogger) +#define cwarn LOG(dev::g_warnLogger) +#define cnote LOG(dev::g_noteLogger) +#define cdebug LOG(dev::g_debugLogger) +#define ctrace LOG(dev::g_traceLogger) + +// Simple non-thread-safe logger with fixed severity and channel for each message +// For better formatting it is recommended to limit channel name to max 6 characters. +inline Logger createLogger(int _severity, std::string const& _channel) +{ + return Logger(_severity, _channel); +} +} // namespace dev + diff --git a/src/eth_client/libdevcore/OverlayDB.cpp b/src/eth_client/libdevcore/OverlayDB.cpp new file mode 100644 index 0000000000..4da6f50644 --- /dev/null +++ b/src/eth_client/libdevcore/OverlayDB.cpp @@ -0,0 +1,147 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include +#include +#include +#include "SHA3.h" +#include "OverlayDB.h" +#include "TrieDB.h" + +namespace dev +{ +namespace +{ +inline db::Slice toSlice(h256 const& _h) +{ + return db::Slice(reinterpret_cast(_h.data()), _h.size); +} + +inline db::Slice toSlice(std::string const& _str) +{ + return db::Slice(_str.data(), _str.size()); +} + +inline db::Slice toSlice(bytes const& _b) +{ + return db::Slice(reinterpret_cast(&_b[0]), _b.size()); +} + +} // namespace + +OverlayDB::~OverlayDB() = default; + +void OverlayDB::commit() +{ + if (m_db) + { + auto writeBatch = m_db->createWriteBatch(); +// cnote << "Committing nodes to disk DB:"; +#if DEV_GUARDED_DB + DEV_READ_GUARDED(x_this) +#endif + { + for (auto const& i: m_main) + { + if (i.second.second) + writeBatch->insert(toSlice(i.first), toSlice(i.second.first)); +// cnote << i.first << "#" << m_main[i.first].second; + } + for (auto const& i: m_aux) + if (i.second.second) + { + bytes b = i.first.asBytes(); + b.push_back(255); // for aux + writeBatch->insert(toSlice(b), toSlice(i.second.first)); + } + } + + for (unsigned i = 0; i < 10; ++i) + { + try + { + m_db->commit(std::move(writeBatch)); + break; + } + catch (boost::exception const& ex) + { + if (i == 9) + { + cwarn << "Fail writing to state database. Bombing out."; + exit(-1); + } + cwarn << "Error writing to state database: " << boost::diagnostic_information(ex); + cwarn << "Sleeping for" << (i + 1) << "seconds, then retrying."; + std::this_thread::sleep_for(std::chrono::seconds(i + 1)); + } + } +#if DEV_GUARDED_DB + DEV_WRITE_GUARDED(x_this) +#endif + { + m_aux.clear(); + m_main.clear(); + } + } +} + +bytes OverlayDB::lookupAux(h256 const& _h) const +{ + bytes ret = StateCacheDB::lookupAux(_h); + if (!ret.empty() || !m_db) + return ret; + + bytes b = _h.asBytes(); + b.push_back(255); // for aux + std::string const v = m_db->lookup(toSlice(b)); + if (v.empty()) + cwarn << "Aux not found: " << _h; + + return asBytes(v); +} + +void OverlayDB::rollback() +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_main.clear(); +} + +std::string OverlayDB::lookup(h256 const& _h) const +{ + std::string ret = StateCacheDB::lookup(_h); + if (!ret.empty() || !m_db) + return ret; + + return m_db->lookup(toSlice(_h)); +} + +bool OverlayDB::exists(h256 const& _h) const +{ + if (StateCacheDB::exists(_h)) + return true; + return m_db && m_db->exists(toSlice(_h)); +} + +void OverlayDB::kill(h256 const& _h) +{ + if (!StateCacheDB::kill(_h)) + { + if (m_db) + { + if (!m_db->exists(toSlice(_h))) + { + // No point node ref decreasing for EmptyTrie since we never bother incrementing it + // in the first place for empty storage tries. + if (_h != EmptyTrie) + cnote << "Decreasing DB node ref count below zero with no DB node. Probably " + "have a corrupt Trie." + << _h; + // TODO: for 1.1: ref-counted triedb. + } + } + } +} + +} diff --git a/src/eth_client/libdevcore/OverlayDB.h b/src/eth_client/libdevcore/OverlayDB.h new file mode 100644 index 0000000000..5ab425a9bc --- /dev/null +++ b/src/eth_client/libdevcore/OverlayDB.h @@ -0,0 +1,50 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include +#include +#include +#include + +namespace dev +{ + +class OverlayDB: public StateCacheDB +{ +public: + explicit OverlayDB(std::unique_ptr _db = nullptr) + : m_db(_db.release(), [](db::DatabaseFace* db) { + clog(VerbosityDebug, "overlaydb") << "Closing state DB"; + delete db; + }) + {} + + ~OverlayDB(); + + // Copyable + OverlayDB(OverlayDB const&) = default; + OverlayDB& operator=(OverlayDB const&) = default; + // Movable + OverlayDB(OverlayDB&&) = default; + OverlayDB& operator=(OverlayDB&&) = default; + + void commit(); + void rollback(); + + std::string lookup(h256 const& _h) const; + bool exists(h256 const& _h) const; + void kill(h256 const& _h); + + bytes lookupAux(h256 const& _h) const; + +private: + using StateCacheDB::clear; + + std::shared_ptr m_db; +}; + +} diff --git a/src/eth_client/libdevcore/RLP.cpp b/src/eth_client/libdevcore/RLP.cpp new file mode 100644 index 0000000000..e44cb44196 --- /dev/null +++ b/src/eth_client/libdevcore/RLP.cpp @@ -0,0 +1,362 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "RLP.h" +using namespace std; +using namespace dev; + +bytes dev::RLPNull = rlp(""); +bytes dev::RLPEmptyList = rlpList(); + +namespace { + +errinfo_comment constructRLPSizeErrorInfo(size_t _actualSize, size_t _dataSize) +{ + std::stringstream s; + s << "Actual size: " << _actualSize << ", data size: " << _dataSize; + return errinfo_comment(s.str()); +} + +} + +RLP::RLP(bytesConstRef _d, Strictness _s): + m_data(_d) +{ + if ((_s & FailIfTooBig) && actualSize() < _d.size()) + { + if (_s & ThrowOnFail) + BOOST_THROW_EXCEPTION(OversizeRLP() << constructRLPSizeErrorInfo(actualSize(), _d.size())); + else + m_data.reset(); + } + if ((_s & FailIfTooSmall) && actualSize() > _d.size()) + { + if (_s & ThrowOnFail) + BOOST_THROW_EXCEPTION(UndersizeRLP() << constructRLPSizeErrorInfo(actualSize(), _d.size())); + else + m_data.reset(); + } +} + +RLP::iterator& RLP::iterator::operator++() +{ + if (m_remaining) + { + m_currentItem.retarget(m_currentItem.next().data(), m_remaining); + m_currentItem = m_currentItem.cropped(0, sizeAsEncoded(m_currentItem)); + m_remaining -= std::min(m_remaining, m_currentItem.size()); + } + else + m_currentItem.retarget(m_currentItem.next().data(), 0); + return *this; +} + +RLP::iterator::iterator(RLP const& _parent, bool _begin) +{ + if (_begin && _parent.isList()) + { + auto pl = _parent.payload(); + m_currentItem = pl.cropped(0, sizeAsEncoded(pl)); + m_remaining = pl.size() - m_currentItem.size(); + } + else + { + m_currentItem = _parent.data().cropped(_parent.data().size()); + m_remaining = 0; + } +} + +RLP RLP::operator[](size_t _i) const +{ + if (_i < m_lastIndex) + { + // Get size of 0th item + m_lastEnd = sizeAsEncoded(payload()); + // Set m_lastItem to 0th item data + m_lastItem = payload().cropped(0, m_lastEnd); + m_lastIndex = 0; + } + for (; m_lastIndex < _i && m_lastItem.size(); ++m_lastIndex) + { + // Get chunk of payload data starting right after m_lastItem + // This will be empty when we're out of bounds + m_lastItem = payload().cropped(m_lastEnd); + // Crop it to get the data of the next item + m_lastItem = m_lastItem.cropped(0, sizeAsEncoded(m_lastItem)); + // Point m_lastEnd to next item + m_lastEnd += m_lastItem.size(); + } + return RLP(m_lastItem, ThrowOnFail | FailIfTooSmall); +} + +size_t RLP::actualSize() const +{ + if (isNull()) + return 0; + if (isSingleByte()) + return 1; + if (isData() || isList()) + return payloadOffset() + length(); + return 0; +} + +void RLP::requireGood() const +{ + if (isNull()) + BOOST_THROW_EXCEPTION(BadRLP()); + byte n = m_data[0]; + if (n != c_rlpDataImmLenStart + 1) + return; + if (m_data.size() < 2) + BOOST_THROW_EXCEPTION(BadRLP()); + if (m_data[1] < c_rlpDataImmLenStart) + BOOST_THROW_EXCEPTION(BadRLP()); +} + +bool RLP::isInt() const +{ + if (isNull()) + return false; + requireGood(); + byte n = m_data[0]; + if (n < c_rlpDataImmLenStart) + return !!n; + else if (n == c_rlpDataImmLenStart) + return true; + else if (n <= c_rlpDataIndLenZero) + { + if (m_data.size() <= 1) + BOOST_THROW_EXCEPTION(BadRLP()); + return m_data[1] != 0; + } + else if (n < c_rlpListStart) + { + if (m_data.size() <= size_t(1 + n - c_rlpDataIndLenZero)) + BOOST_THROW_EXCEPTION(BadRLP()); + return m_data[1 + n - c_rlpDataIndLenZero] != 0; + } + else + return false; + return false; +} + +size_t RLP::length() const +{ + if (isNull()) + return 0; + requireGood(); + size_t ret = 0; + byte const n = m_data[0]; + if (n < c_rlpDataImmLenStart) + return 1; + else if (n <= c_rlpDataIndLenZero) + return n - c_rlpDataImmLenStart; + else if (n < c_rlpListStart) + { + if (m_data.size() <= size_t(n - c_rlpDataIndLenZero)) + BOOST_THROW_EXCEPTION(BadRLP()); + if (m_data.size() > 1) + if (m_data[1] == 0) + BOOST_THROW_EXCEPTION(BadRLP()); + unsigned lengthSize = n - c_rlpDataIndLenZero; + if (lengthSize > sizeof(ret)) + // We did not check, but would most probably not fit in our memory. + BOOST_THROW_EXCEPTION(UndersizeRLP()); + // No leading zeroes. + if (!m_data[1]) + BOOST_THROW_EXCEPTION(BadRLP()); + for (unsigned i = 0; i < lengthSize; ++i) + ret = (ret << 8) | m_data[i + 1]; + // Must be greater than the limit. + if (ret < c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes) + BOOST_THROW_EXCEPTION(BadRLP()); + } + else if (n <= c_rlpListIndLenZero) + return n - c_rlpListStart; + else + { + unsigned lengthSize = n - c_rlpListIndLenZero; + if (m_data.size() <= lengthSize) + BOOST_THROW_EXCEPTION(BadRLP()); + if (m_data.size() > 1) + if (m_data[1] == 0) + BOOST_THROW_EXCEPTION(BadRLP()); + if (lengthSize > sizeof(ret)) + // We did not check, but would most probably not fit in our memory. + BOOST_THROW_EXCEPTION(UndersizeRLP()); + if (!m_data[1]) + BOOST_THROW_EXCEPTION(BadRLP()); + for (unsigned i = 0; i < lengthSize; ++i) + ret = (ret << 8) | m_data[i + 1]; + if (ret < 0x100 - c_rlpListStart - c_rlpMaxLengthBytes) + BOOST_THROW_EXCEPTION(BadRLP()); + } + // We have to be able to add payloadOffset to length without overflow. + // This rejects roughly 4GB-sized RLPs on some platforms. + if (ret >= std::numeric_limits::max() - 0x100) + BOOST_THROW_EXCEPTION(UndersizeRLP()); + return ret; +} + +size_t RLP::items() const +{ + if (isList()) + { + bytesConstRef d = payload(); + size_t i = 0; + for (; d.size(); ++i) + d = d.cropped(sizeAsEncoded(d)); + return i; + } + return 0; +} + +RLPStream& RLPStream::appendRaw(bytesConstRef _s, size_t _itemCount) +{ + m_out.insert(m_out.end(), _s.begin(), _s.end()); + noteAppended(_itemCount); + return *this; +} + +void RLPStream::noteAppended(size_t _itemCount) +{ + if (!_itemCount) + return; +// cdebug << "noteAppended(" << _itemCount << ")"; + while (m_listStack.size()) + { + if (m_listStack.back().first < _itemCount) + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large") << RequirementError((bigint)m_listStack.back().first, (bigint)_itemCount)); + m_listStack.back().first -= _itemCount; + if (m_listStack.back().first) + break; + else + { + auto p = m_listStack.back().second; + m_listStack.pop_back(); + size_t s = m_out.size() - p; // list size + auto brs = bytesRequired(s); + unsigned encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs); +// cdebug << "s: " << s << ", p: " << p << ", m_out.size(): " << m_out.size() << ", encodeSize: " << encodeSize << " (br: " << brs << ")"; + auto os = m_out.size(); + m_out.resize(os + encodeSize); + memmove(m_out.data() + p + encodeSize, m_out.data() + p, os - p); + if (s < c_rlpListImmLenCount) + m_out[p] = (byte)(c_rlpListStart + s); + else if (c_rlpListIndLenZero + brs <= 0xff) + { + m_out[p] = (byte)(c_rlpListIndLenZero + brs); + byte* b = &(m_out[p + brs]); + for (; s; s >>= 8) + *(b--) = (byte)s; + } + else + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large for RLP")); + } + _itemCount = 1; // for all following iterations, we've effectively appended a single item only since we completed a list. + } +} + +RLPStream& RLPStream::appendList(size_t _items) +{ +// cdebug << "appendList(" << _items << ")"; + if (_items) + m_listStack.push_back(std::make_pair(_items, m_out.size())); + else + appendList(bytes()); + return *this; +} + +RLPStream& RLPStream::appendList(bytesConstRef _rlp) +{ + if (_rlp.size() < c_rlpListImmLenCount) + m_out.push_back((byte)(_rlp.size() + c_rlpListStart)); + else + pushCount(_rlp.size(), c_rlpListIndLenZero); + appendRaw(_rlp, 1); + return *this; +} + +RLPStream& RLPStream::append(bytesConstRef _s, bool _compact) +{ + size_t s = _s.size(); + byte const* d = _s.data(); + if (_compact) + for (size_t i = 0; i < _s.size() && !*d; ++i, --s, ++d) {} + + if (s == 1 && *d < c_rlpDataImmLenStart) + m_out.push_back(*d); + else + { + if (s < c_rlpDataImmLenCount) + m_out.push_back((byte)(s + c_rlpDataImmLenStart)); + else + pushCount(s, c_rlpDataIndLenZero); + appendRaw(bytesConstRef(d, s), 0); + } + noteAppended(); + return *this; +} + +RLPStream& RLPStream::append(bigint _i) +{ + if (!_i) + m_out.push_back(c_rlpDataImmLenStart); + else if (_i < c_rlpDataImmLenStart) + m_out.push_back((byte)_i); + else + { + unsigned br = bytesRequired(_i); + if (br < c_rlpDataImmLenCount) + m_out.push_back((byte)(br + c_rlpDataImmLenStart)); + else + { + auto brbr = bytesRequired(br); + if (c_rlpDataIndLenZero + brbr > 0xff) + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Number too large for RLP")); + m_out.push_back((byte)(c_rlpDataIndLenZero + brbr)); + pushInt(br, brbr); + } + pushInt(_i, br); + } + noteAppended(); + return *this; +} + +void RLPStream::pushCount(size_t _count, byte _base) +{ + auto br = bytesRequired(_count); + if (int(br) + _base > 0xff) + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Count too large for RLP")); + m_out.push_back((byte)(br + _base)); // max 8 bytes. + pushInt(_count, br); +} + +static void streamOut(std::ostream& _out, dev::RLP const& _d, unsigned _depth = 0) +{ + if (_depth > 64) + _out << ""; + else if (_d.isNull()) + _out << "null"; + else if (_d.isInt()) + _out << std::showbase << std::hex << std::nouppercase << _d.toInt(RLP::LaissezFaire) << dec; + else if (_d.isData()) + _out << escaped(_d.toString(), false); + else if (_d.isList()) + { + _out << "["; + int j = 0; + for (auto i: _d) + { + _out << (j++ ? ", " : " "); + streamOut(_out, i, _depth + 1); + } + _out << " ]"; + } +} + +std::ostream& dev::operator<<(std::ostream& _out, RLP const& _d) +{ + streamOut(_out, _d); + return _out; +} diff --git a/src/eth_client/libdevcore/RLP.h b/src/eth_client/libdevcore/RLP.h new file mode 100644 index 0000000000..5e93bbd708 --- /dev/null +++ b/src/eth_client/libdevcore/RLP.h @@ -0,0 +1,472 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// Recursive Linear-Prefix serialization / deserialization. +#pragma once + +#include "Exceptions.h" +#include "FixedHash.h" +#include "vector_ref.h" + +#include +#include +#include +#include +#include + +namespace dev +{ + +class RLP; + +template struct intTraits { static const unsigned maxSize = sizeof(_T); }; +template <> struct intTraits { static const unsigned maxSize = 20; }; +template <> struct intTraits { static const unsigned maxSize = 32; }; +template <> struct intTraits { static const unsigned maxSize = ~(unsigned)0; }; + +static const byte c_rlpMaxLengthBytes = 8; +static const byte c_rlpDataImmLenStart = 0x80; +static const byte c_rlpListStart = 0xc0; + +static const byte c_rlpDataImmLenCount = c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes; +static const byte c_rlpDataIndLenZero = c_rlpDataImmLenStart + c_rlpDataImmLenCount - 1; +static const byte c_rlpListImmLenCount = 256 - c_rlpListStart - c_rlpMaxLengthBytes; +static const byte c_rlpListIndLenZero = c_rlpListStart + c_rlpListImmLenCount - 1; + +template struct Converter { static T convert(RLP const&, int) { BOOST_THROW_EXCEPTION(BadCast()); } }; + +/** + * Class for interpreting Recursive Linear-Prefix Data. + */ +class RLP +{ +public: + /// Conversion flags + enum + { + AllowNonCanon = 1, + ThrowOnFail = 4, + FailIfTooBig = 8, + FailIfTooSmall = 16, + Strict = ThrowOnFail | FailIfTooBig, + VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall, + LaissezFaire = AllowNonCanon + }; + + using Strictness = int; + + /// Construct a null node. + RLP() {} + + /// Construct a node of value given in the bytes. + explicit RLP(bytesConstRef _d, Strictness _s = VeryStrict); + + /// Construct a node of value given in the bytes. + explicit RLP(bytes const& _d, Strictness _s = VeryStrict): RLP(&_d, _s) {} + + /// Construct a node to read RLP data in the bytes given. + RLP(byte const* _b, unsigned _s, Strictness _st = VeryStrict): RLP(bytesConstRef(_b, _s), _st) {} + + /// Construct a node to read RLP data in the string. + explicit RLP(std::string const& _s, Strictness _st = VeryStrict): RLP(bytesConstRef((byte const*)_s.data(), _s.size()), _st) {} + + /// The bare data of the RLP. + bytesConstRef data() const { return m_data; } + + /// @returns true if the RLP is non-null. + explicit operator bool() const { return !isNull(); } + + /// No value. + bool isNull() const { return m_data.size() == 0; } + + /// Contains a zero-length string or zero-length list. + bool isEmpty() const { return !isNull() && (m_data[0] == c_rlpDataImmLenStart || m_data[0] == c_rlpListStart); } + + /// String value. + bool isData() const { return !isNull() && m_data[0] < c_rlpListStart; } + + /// List value. + bool isList() const { return !isNull() && m_data[0] >= c_rlpListStart; } + + /// Integer value. Must not have a leading zero. + bool isInt() const; + + /// @returns the number of items in the list, or zero if it isn't a list. + size_t itemCount() const { return isList() ? items() : 0; } + size_t itemCountStrict() const { if (!isList()) BOOST_THROW_EXCEPTION(BadCast()); return items(); } + + /// @returns the number of bytes in the data, or zero if it isn't data. + size_t size() const { return isData() ? length() : 0; } + size_t sizeStrict() const { if (!isData()) BOOST_THROW_EXCEPTION(BadCast()); return length(); } + + /// Equality operators; does best-effort conversion and checks for equality. + bool operator==(char const* _s) const { return isData() && toString() == _s; } + bool operator!=(char const* _s) const { return isData() && toString() != _s; } + bool operator==(std::string const& _s) const { return isData() && toString() == _s; } + bool operator!=(std::string const& _s) const { return isData() && toString() != _s; } + template bool operator==(FixedHash<_N> const& _h) const { return isData() && toHash<_N>() == _h; } + template bool operator!=(FixedHash<_N> const& _s) const { return isData() && toHash<_N>() != _s; } + bool operator==(unsigned const& _i) const { return isInt() && toInt() == _i; } + bool operator!=(unsigned const& _i) const { return isInt() && toInt() != _i; } + bool operator==(u256 const& _i) const { return isInt() && toInt() == _i; } + bool operator!=(u256 const& _i) const { return isInt() && toInt() != _i; } + bool operator==(bigint const& _i) const { return isInt() && toInt() == _i; } + bool operator!=(bigint const& _i) const { return isInt() && toInt() != _i; } + + /// Subscript operator. + /// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise. + /// @note if used to access items in ascending order, this is efficient. + RLP operator[](size_t _i) const; + + using element_type = RLP; + + /// @brief Iterator class for iterating through items of RLP list. + class iterator + { + friend class RLP; + + public: + using value_type = RLP; + using element_type = RLP; + + iterator& operator++(); + iterator operator++(int) { auto ret = *this; operator++(); return ret; } + RLP operator*() const { return RLP(m_currentItem); } + bool operator==(iterator const& _cmp) const { return m_currentItem == _cmp.m_currentItem; } + bool operator!=(iterator const& _cmp) const { return !operator==(_cmp); } + + private: + iterator() {} + iterator(RLP const& _parent, bool _begin); + + size_t m_remaining = 0; + bytesConstRef m_currentItem; + }; + + /// @brief Iterator into beginning of sub-item list (valid only if we are a list). + iterator begin() const { return iterator(*this, true); } + + /// @brief Iterator into end of sub-item list (valid only if we are a list). + iterator end() const { return iterator(*this, false); } + + template inline T convert(int _flags) const; + + /// Best-effort conversion operators. + explicit operator std::string() const { return toString(); } + explicit operator bytes() const { return toBytes(); } + explicit operator uint8_t() const { return toInt(); } + explicit operator uint16_t() const { return toInt(); } + explicit operator uint32_t() const { return toInt(); } + explicit operator uint64_t() const { return toInt(); } + explicit operator u160() const { return toInt(); } + explicit operator u256() const { return toInt(); } + explicit operator bigint() const { return toInt(); } + template explicit operator FixedHash() const { return toHash>(); } + template explicit operator std::pair() const { return toPair(); } + template explicit operator std::vector() const { return toVector(); } + template explicit operator std::set() const { return toSet(); } + template explicit operator std::array() const { return toArray(); } + + /// Converts to bytearray. @returns the empty byte array if not a string. + bytes toBytes(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return bytes(); } return bytes(payload().data(), payload().data() + length()); } + /// Converts to bytearray. @returns the empty byte array if not a string. + bytesConstRef toBytesConstRef(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return bytesConstRef(); } return payload().cropped(0, length()); } + /// Converts to string. @returns the empty string if not a string. + std::string toString(int _flags = LaissezFaire) const { if (!isData()) { if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else return std::string(); } return payload().cropped(0, length()).toString(); } + /// Converts to string. @throws BadCast if not a string. + std::string toStringStrict() const { return toString(Strict); } + + template + std::vector toVector(int _flags = LaissezFaire) const + { + std::vector ret; + if (isList()) + { + ret.reserve(itemCount()); + for (auto const& i: *this) + ret.push_back(i.convert(_flags)); + } + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template + std::set toSet(int _flags = LaissezFaire) const + { + std::set ret; + if (isList()) + for (auto const& i: *this) + ret.insert(i.convert(_flags)); + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template + std::unordered_set toUnorderedSet(int _flags = LaissezFaire) const + { + std::unordered_set ret; + if (isList()) + for (auto const& i: *this) + ret.insert(i.convert(_flags)); + else if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + return ret; + } + + template + std::pair toPair(int _flags = Strict) const + { + std::pair ret; + if (itemCountStrict() != 2) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return ret; + } + ret.first = (*this)[0].convert(_flags); + ret.second = (*this)[1].convert(_flags); + return ret; + } + + template + std::array toArray(int _flags = LaissezFaire) const + { + if (itemCount() != N) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return std::array(); + } + std::array ret; + for (size_t i = 0; i < N; ++i) + ret[i] = operator[](i).convert(_flags); + return ret; + } + + /// Converts to int of type given; if isData(), decodes as big-endian bytestream. @returns 0 if not an int or data. + template _T toInt(int _flags = Strict) const + { + requireGood(); + if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull()) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return 0; + } + + auto p = payload(); + if (p.size() > intTraits<_T>::maxSize && (_flags & FailIfTooBig)) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return 0; + } + + return fromBigEndian<_T>(p); + } + + int64_t toPositiveInt64(int _flags = Strict) const + { + int64_t i = toInt(_flags); + if ((_flags & ThrowOnFail) && i < 0) + BOOST_THROW_EXCEPTION(BadCast()); + return i; + } + + template _N toHash(int _flags = Strict) const + { + requireGood(); + auto p = payload(); + auto l = p.size(); + if (!isData() || (l > _N::size && (_flags & FailIfTooBig)) || (l < _N::size && (_flags & FailIfTooSmall))) + { + if (_flags & ThrowOnFail) + BOOST_THROW_EXCEPTION(BadCast()); + else + return _N(); + } + + _N ret; + size_t s = std::min(_N::size, l); + memcpy(ret.data() + _N::size - s, p.data(), s); + return ret; + } + + /// @returns the data payload. Valid for all types. + bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) BOOST_THROW_EXCEPTION(BadRLP()); return m_data.cropped(payloadOffset(), l); } + + /// @returns the theoretical size of this item as encoded in the data. + /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. + size_t actualSize() const; + +private: + /// Disable construction from rvalue + explicit RLP(bytes const&&) {} + + /// Throws if is non-canonical data (i.e. single byte done in two bytes that could be done in one). + void requireGood() const; + + /// Single-byte data payload. + bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; } + + /// @returns the amount of bytes used to encode the length of the data. Valid for all types. + unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; } + + /// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data. + size_t length() const; + + /// @returns the number of bytes into the data that the payload starts. + size_t payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); } + + /// @returns the number of data items. + size_t items() const; + + /// @returns the size encoded into the RLP in @a _data and throws if _data is too short. + static size_t sizeAsEncoded(bytesConstRef _data) { return RLP(_data, ThrowOnFail | FailIfTooSmall).actualSize(); } + + /// Our byte data. + bytesConstRef m_data; + + /// The list-indexing cache. + // Index of the last item accessed with operator[] + mutable size_t m_lastIndex = (size_t)-1; + // Offset of the next byte after last byte of m_lastItem + mutable size_t m_lastEnd = 0; + // Data of the last item accessed with operator[] + mutable bytesConstRef m_lastItem; +}; + +template <> struct Converter { static std::string convert(RLP const& _r, int _flags) { return _r.toString(_flags); } }; +template <> struct Converter { static bytes convert(RLP const& _r, int _flags) { return _r.toBytes(_flags); } }; +template <> struct Converter { static uint8_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static uint16_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static uint32_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static uint64_t convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static u160 convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static u256 convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template <> struct Converter { static bigint convert(RLP const& _r, int _flags) { return _r.toInt(_flags); } }; +template struct Converter> { static FixedHash convert(RLP const& _r, int _flags) { return _r.toHash>(_flags); } }; +template struct Converter> { static std::pair convert(RLP const& _r, int _flags) { return _r.toPair(_flags); } }; +template struct Converter> { static std::vector convert(RLP const& _r, int _flags) { return _r.toVector(_flags); } }; +template struct Converter> { static std::set convert(RLP const& _r, int _flags) { return _r.toSet(_flags); } }; +template struct Converter> { static std::unordered_set convert(RLP const& _r, int _flags) { return _r.toUnorderedSet(_flags); } }; +template struct Converter> { static std::array convert(RLP const& _r, int _flags) { return _r.toArray(_flags); } }; + +template inline T RLP::convert(int _flags) const { return Converter::convert(*this, _flags); } + +/** + * @brief Class for writing to an RLP bytestream. + */ +class RLPStream +{ +public: + /// Initializes empty RLPStream. + RLPStream() {} + + /// Initializes the RLPStream as a list of @a _listItems items. + explicit RLPStream(size_t _listItems) { appendList(_listItems); } + + ~RLPStream() {} + + /// Append given datum to the byte stream. + RLPStream& append(unsigned _s) { return append(bigint(_s)); } + RLPStream& append(u160 _s) { return append(bigint(_s)); } + RLPStream& append(u256 _s) { return append(bigint(_s)); } + RLPStream& append(bigint _s); + RLPStream& append(bytesConstRef _s, bool _compact = false); + RLPStream& append(bytes const& _s) { return append(bytesConstRef(&_s)); } + RLPStream& append(std::string const& _s) { return append(bytesConstRef(_s)); } + RLPStream& append(char const* _s) { return append(std::string(_s)); } + template RLPStream& append(FixedHash _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); } + + /// Appends an arbitrary RLP fragment - this *must* be a single item unless @a _itemCount is given. + RLPStream& append(RLP const& _rlp, size_t _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } + + /// Appends a sequence of data to the stream as a list. + template RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); } + template RLPStream& appendVector(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template RLPStream& append(std::set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template RLPStream& append(std::unordered_set<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; } + template RLPStream& append(std::pair const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; } + + /// Appends a list. + RLPStream& appendList(size_t _items); + RLPStream& appendList(bytesConstRef _rlp); + RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); } + RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); } + + /// Appends raw (pre-serialised) RLP data. Use with caution. + RLPStream& appendRaw(bytesConstRef _rlp, size_t _itemCount = 1); + RLPStream& appendRaw(bytes const& _rlp, size_t _itemCount = 1) { return appendRaw(&_rlp, _itemCount); } + + /// Shift operators for appending data items. + template RLPStream& operator<<(T _data) { return append(_data); } + + /// Clear the output stream so far. + void clear() { m_out.clear(); m_listStack.clear(); } + + /// Read the byte stream. + bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + + /// Swap the contents of the output stream out for some other byte array. + void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } + +private: + void noteAppended(size_t _itemCount = 1); + + /// Push the node-type byte (using @a _base) along with the item count @a _count. + /// @arg _count is number of characters for strings, data-bytes for ints, or items for lists. + void pushCount(size_t _count, byte _offset); + + /// Push an integer as a raw big-endian byte-stream. + template void pushInt(_T _i, size_t _br) + { + m_out.resize(m_out.size() + _br); + byte* b = &m_out.back(); + for (; _i; _i >>= 8) + *(b--) = toUint8(_i); + } + + /// Our output byte stream. + bytes m_out; + + std::vector> m_listStack; +}; + +template void rlpListAux(RLPStream& _out, _T _t) { _out << _t; } +template void rlpListAux(RLPStream& _out, _T _t, _Ts ... _ts) { rlpListAux(_out << _t, _ts...); } + +/// Export a single item in RLP format, returning a byte array. +template bytes rlp(_T _t) { return (RLPStream() << _t).out(); } + +/// Export a list of items in RLP format, returning a byte array. +inline bytes rlpList() { return RLPStream(0).out(); } +template bytes rlpList(_Ts ... _ts) +{ + RLPStream out(sizeof ...(_Ts)); + rlpListAux(out, _ts...); + return out.out(); +} + +/// The empty string in RLP format. +extern bytes RLPNull; + +/// The empty list in RLP format. +extern bytes RLPEmptyList; + +/// Human readable version of RLP. +std::ostream& operator<<(std::ostream& _out, dev::RLP const& _d); + +} diff --git a/src/eth_client/libdevcore/SHA3.cpp b/src/eth_client/libdevcore/SHA3.cpp new file mode 100644 index 0000000000..fb9b624831 --- /dev/null +++ b/src/eth_client/libdevcore/SHA3.cpp @@ -0,0 +1,23 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "SHA3.h" +#include "RLP.h" + +#include + +namespace dev +{ +h256 const EmptySHA3 = sha3(bytesConstRef()); +h256 const EmptyListSHA3 = sha3(rlpList()); + +bool sha3(bytesConstRef _input, bytesRef o_output) noexcept +{ + if (o_output.size() != 32) + return false; + ethash::hash256 h = ethash::keccak256(_input.data(), _input.size()); + bytesConstRef{h.bytes, 32}.copyTo(o_output); + return true; +} +} // namespace dev diff --git a/src/eth_client/libdevcore/SHA3.h b/src/eth_client/libdevcore/SHA3.h new file mode 100644 index 0000000000..205579678f --- /dev/null +++ b/src/eth_client/libdevcore/SHA3.h @@ -0,0 +1,119 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "FixedHash.h" +#include "vector_ref.h" + +#include + +#include + +namespace dev +{ + +// SHA-3 convenience routines. + +/// Calculate SHA3-256 hash of the given input and load it into the given output. +/// @returns false if o_output.size() != 32. +bool sha3(bytesConstRef _input, bytesRef o_output) noexcept; + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +inline h256 sha3(bytesConstRef _input) noexcept +{ + h256 ret; + sha3(_input, ret.ref()); + return ret; +} + +inline SecureFixedHash<32> sha3Secure(bytesConstRef _input) noexcept +{ + SecureFixedHash<32> ret; + sha3(_input, ret.writable().ref()); + return ret; +} + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +inline h256 sha3(bytes const& _input) noexcept +{ + return sha3(bytesConstRef(&_input)); +} + +inline SecureFixedHash<32> sha3Secure(bytes const& _input) noexcept +{ + return sha3Secure(bytesConstRef(&_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) noexcept +{ + return sha3(bytesConstRef(_input)); +} + +inline SecureFixedHash<32> sha3Secure(std::string const& _input) noexcept +{ + return sha3Secure(bytesConstRef(_input)); +} + +/// Keccak hash variant optimized for hashing 256-bit hashes. +inline h256 sha3(h256 const& _input) noexcept +{ + ethash::hash256 hash = ethash::keccak256_32(_input.data()); + return h256{hash.bytes, h256::ConstructFromPointer}; +} + +/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. +template +inline h256 sha3(FixedHash const& _input) noexcept +{ + return sha3(_input.ref()); +} + +template +inline SecureFixedHash<32> sha3Secure(FixedHash const& _input) noexcept +{ + return sha3Secure(_input.ref()); +} + +/// Fully secure variants are equivalent for sha3 and sha3Secure. +inline SecureFixedHash<32> sha3(bytesSec const& _input) noexcept +{ + return sha3Secure(_input.ref()); +} + +inline SecureFixedHash<32> sha3Secure(bytesSec const& _input) noexcept +{ + return sha3Secure(_input.ref()); +} + +template +inline SecureFixedHash<32> sha3(SecureFixedHash const& _input) noexcept +{ + return sha3Secure(_input.ref()); +} + +template +inline SecureFixedHash<32> sha3Secure(SecureFixedHash const& _input) noexcept +{ + return sha3Secure(_input.ref()); +} + +/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. +inline std::string sha3(std::string const& _input, bool _isNibbles) +{ + return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); +} + +/// Calculate SHA3-256 MAC +inline void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) +{ + sha3(_secret.toBytes() + _plain.toBytes()).ref().populate(_output); +} + +extern h256 const EmptySHA3; + +extern h256 const EmptyListSHA3; + +} diff --git a/src/eth_client/libdevcore/StateCacheDB.cpp b/src/eth_client/libdevcore/StateCacheDB.cpp new file mode 100644 index 0000000000..17f2bb57f8 --- /dev/null +++ b/src/eth_client/libdevcore/StateCacheDB.cpp @@ -0,0 +1,155 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "StateCacheDB.h" +#include "Common.h" +#include "CommonData.h" +using namespace std; +using namespace dev; + +namespace dev +{ + +std::unordered_map StateCacheDB::get() const +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + std::unordered_map ret; + for (auto const& i: m_main) + if (!m_enforceRefs || i.second.second > 0) + ret.insert(make_pair(i.first, i.second.first)); + return ret; +} + +StateCacheDB& StateCacheDB::operator=(StateCacheDB const& _c) +{ + if (this == &_c) + return *this; +#if DEV_GUARDED_DB + ReadGuard l(_c.x_this); + WriteGuard l2(x_this); +#endif + m_main = _c.m_main; + m_aux = _c.m_aux; + return *this; +} + +std::string StateCacheDB::lookup(h256 const& _h) const +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + auto it = m_main.find(_h); + if (it != m_main.end()) + { + if (!m_enforceRefs || it->second.second > 0) + return it->second.first; + else + cwarn << "Lookup required for value with refcount == 0. This is probably a critical trie issue" << _h; + } + return std::string(); +} + +bool StateCacheDB::exists(h256 const& _h) const +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + auto it = m_main.find(_h); + if (it != m_main.end() && (!m_enforceRefs || it->second.second > 0)) + return true; + return false; +} + +void StateCacheDB::insert(h256 const& _h, bytesConstRef _v) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + auto it = m_main.find(_h); + if (it != m_main.end()) + { + it->second.first = _v.toString(); + it->second.second++; + } + else + m_main[_h] = make_pair(_v.toString(), 1); +} + +bool StateCacheDB::kill(h256 const& _h) +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + if (m_main.count(_h)) + { + if (m_main[_h].second > 0) + { + m_main[_h].second--; + return true; + } + } + return false; +} + +bytes StateCacheDB::lookupAux(h256 const& _h) const +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + auto it = m_aux.find(_h); + if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) + return it->second.first; + return bytes(); +} + +void StateCacheDB::removeAux(h256 const& _h) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_aux[_h].second = false; +} + +void StateCacheDB::insertAux(h256 const& _h, bytesConstRef _v) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_aux[_h] = make_pair(_v.toBytes(), true); +} + +void StateCacheDB::purge() +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + // purge m_main + for (auto it = m_main.begin(); it != m_main.end(); ) + if (it->second.second) + ++it; + else + it = m_main.erase(it); + + // purge m_aux + for (auto it = m_aux.begin(); it != m_aux.end(); ) + if (it->second.second) + ++it; + else + it = m_aux.erase(it); +} + +h256Hash StateCacheDB::keys() const +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + h256Hash ret; + for (auto const& i: m_main) + if (i.second.second) + ret.insert(i.first); + return ret; +} + +} diff --git a/src/eth_client/libdevcore/StateCacheDB.h b/src/eth_client/libdevcore/StateCacheDB.h new file mode 100644 index 0000000000..b9c2e14903 --- /dev/null +++ b/src/eth_client/libdevcore/StateCacheDB.h @@ -0,0 +1,79 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#pragma once + +#include "Common.h" +#include "Log.h" +#include "RLP.h" + +namespace dev +{ +class StateCacheDB +{ + friend class EnforceRefs; + +public: + StateCacheDB() {} + StateCacheDB(StateCacheDB const& _c) { operator=(_c); } + + StateCacheDB& operator=(StateCacheDB const& _c); + + virtual ~StateCacheDB() = default; + + void clear() + { + m_main.clear(); + m_aux.clear(); + } // WARNING !!!! didn't originally clear m_refCount!!! + std::unordered_map get() const; + + std::string lookup(h256 const& _h) const; + bool exists(h256 const& _h) const; + void insert(h256 const& _h, bytesConstRef _v); + bool kill(h256 const& _h); + void purge(); + + bytes lookupAux(h256 const& _h) const; + void removeAux(h256 const& _h); + void insertAux(h256 const& _h, bytesConstRef _v); + + h256Hash keys() const; + +protected: +#if DEV_GUARDED_DB + mutable SharedMutex x_this; +#endif + std::unordered_map> m_main; + std::unordered_map> m_aux; + + mutable bool m_enforceRefs = false; +}; + +class EnforceRefs +{ +public: + EnforceRefs(StateCacheDB const& _o, bool _r) : m_o(_o), m_r(_o.m_enforceRefs) + { + _o.m_enforceRefs = _r; + } + ~EnforceRefs() { m_o.m_enforceRefs = m_r; } + +private: + StateCacheDB const& m_o; + bool m_r; +}; + +inline std::ostream& operator<<(std::ostream& _out, StateCacheDB const& _m) +{ + for (auto const& i : _m.get()) + { + _out << i.first << ": "; + _out << RLP(i.second); + _out << " " << toHex(i.second); + _out << std::endl; + } + return _out; +} + +} // namespace dev diff --git a/src/eth_client/libdevcore/TrieCommon.cpp b/src/eth_client/libdevcore/TrieCommon.cpp new file mode 100644 index 0000000000..9de78f1caf --- /dev/null +++ b/src/eth_client/libdevcore/TrieCommon.cpp @@ -0,0 +1,113 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "TrieCommon.h" +#include "SHA3.h" + +namespace dev +{ + +h256 const EmptyTrie = sha3(rlp("")); + +/* + * Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1 + * NOTE: the "termination marker" and "leaf-node" specifier are completely equivalent. + * [0,0,1,2,3,4,5] 0x10012345 + * [0,1,2,3,4,5] 0x00012345 + * [1,2,3,4,5] 0x112345 + * [0,0,1,2,3,4] 0x00001234 + * [0,1,2,3,4] 0x101234 + * [1,2,3,4] 0x001234 + * [0,0,1,2,3,4,5,T] 0x30012345 + * [0,0,1,2,3,4,T] 0x20001234 + * [0,1,2,3,4,5,T] 0x20012345 + * [1,2,3,4,5,T] 0x312345 + * [1,2,3,4,T] 0x201234 + */ + +std::string hexPrefixEncode(bytes const& _hexVector, bool _leaf, int _begin, int _end) +{ + unsigned begin = _begin; + unsigned end = _end < 0 ? _hexVector.size() + 1 + _end : _end; + bool odd = ((end - begin) % 2) != 0; + + std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16); + if (odd) + { + ret[0] |= _hexVector[begin]; + ++begin; + } + for (unsigned i = begin; i < end; i += 2) + ret += _hexVector[i] * 16 + _hexVector[i + 1]; + return ret; +} + +std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset) +{ + unsigned begin = _beginNibble + _offset; + unsigned end = (_endNibble < 0 ? ((int)(_data.size() * 2 - _offset) + 1) + _endNibble : _endNibble) + _offset; + bool odd = (end - begin) & 1; + + std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16); + ret.reserve((end - begin) / 2 + 1); + + unsigned d = odd ? 1 : 2; + for (auto i = begin; i < end; ++i, ++d) + { + byte n = nibble(_data, i); + if (d & 1) // odd + ret.back() |= n; // or the nibble onto the back + else + ret.push_back(n << 4); // push the nibble on to the back << 4 + } + return ret; +} + +std::string hexPrefixEncode(bytesConstRef _d1, unsigned _o1, bytesConstRef _d2, unsigned _o2, bool _leaf) +{ + unsigned begin1 = _o1; + unsigned end1 = _d1.size() * 2; + unsigned begin2 = _o2; + unsigned end2 = _d2.size() * 2; + + bool odd = (end1 - begin1 + end2 - begin2) & 1; + + std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16); + ret.reserve((end1 - begin1 + end2 - begin2) / 2 + 1); + + unsigned d = odd ? 1 : 2; + for (auto i = begin1; i < end1; ++i, ++d) + { + byte n = nibble(_d1, i); + if (d & 1) // odd + ret.back() |= n; // or the nibble onto the back + else + ret.push_back(n << 4); // push the nibble on to the back << 4 + } + for (auto i = begin2; i < end2; ++i, ++d) + { + byte n = nibble(_d2, i); + if (d & 1) // odd + ret.back() |= n; // or the nibble onto the back + else + ret.push_back(n << 4); // push the nibble on to the back << 4 + } + return ret; +} + +byte uniqueInUse(RLP const& _orig, byte except) +{ + byte used = 255; + for (unsigned i = 0; i < 17; ++i) + if (i != except && !_orig[i].isEmpty()) + { + if (used == 255) + used = (byte)i; + else + return 255; + } + return used; +} + +} diff --git a/src/eth_client/libdevcore/TrieCommon.h b/src/eth_client/libdevcore/TrieCommon.h new file mode 100644 index 0000000000..2d88a7a9ec --- /dev/null +++ b/src/eth_client/libdevcore/TrieCommon.h @@ -0,0 +1,117 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "Common.h" +#include "RLP.h" + +namespace dev +{ +extern const h256 EmptyTrie; + +inline byte nibble(bytesConstRef _data, unsigned _i) +{ + return (_i & 1) ? (_data[_i / 2] & 15) : (_data[_i / 2] >> 4); +} + +/// Interprets @a _first and @a _second as vectors of nibbles and returns the length of the longest common +/// prefix of _first[_beginFirst..._endFirst] and _second[_beginSecond..._endSecond]. +inline unsigned sharedNibbles(bytesConstRef _first, unsigned _beginFirst, unsigned _endFirst, bytesConstRef _second, unsigned _beginSecond, unsigned _endSecond) +{ + unsigned ret = 0; + while (_beginFirst < _endFirst && _beginSecond < _endSecond && nibble(_first, _beginFirst) == nibble(_second, _beginSecond)) + { + ++_beginFirst; + ++_beginSecond; + ++ret; + } + return ret; +} + +/** + * Nibble-based view on a bytesConstRef. + */ +struct NibbleSlice +{ + bytesConstRef data; + unsigned offset; + + NibbleSlice(bytesConstRef _data = bytesConstRef(), unsigned _offset = 0): data(_data), offset(_offset) {} + byte operator[](unsigned _index) const { return nibble(data, offset + _index); } + unsigned size() const { return data.size() * 2 - offset; } + bool empty() const { return !size(); } + NibbleSlice mid(unsigned _index) const { return NibbleSlice(data, offset + _index); } + void clear() { data.reset(); offset = 0; } + + /// @returns true iff _k is a prefix of this. + bool contains(NibbleSlice _k) const { return shared(_k) == _k.size(); } + /// @returns the number of shared nibbles at the beginning of this and _k. + unsigned shared(NibbleSlice _k) const { return sharedNibbles(data, offset, offset + size(), _k.data, _k.offset, _k.offset + _k.size()); } + /** + * @brief Determine if we, a full key, are situated prior to a particular key-prefix. + * @param _k The prefix. + * @return true if we are strictly prior to the prefix. + */ + bool isEarlierThan(NibbleSlice _k) const + { + unsigned i = 0; + for (; i < _k.size() && i < size(); ++i) + if (operator[](i) < _k[i]) // Byte is lower - we're earlier.. + return true; + else if (operator[](i) > _k[i]) // Byte is higher - we're not earlier. + return false; + if (i >= _k.size()) // Ran past the end of the prefix - we're == for the entire prefix - we're not earlier. + return false; + return true; // Ran out before the prefix had finished - we're earlier. + } + bool operator==(NibbleSlice _k) const { return _k.size() == size() && shared(_k) == _k.size(); } + bool operator!=(NibbleSlice _s) const { return !operator==(_s); } +}; + +inline std::ostream& operator<<(std::ostream& _out, NibbleSlice const& _m) +{ + for (unsigned i = 0; i < _m.size(); ++i) + _out << std::hex << (int)_m[i] << std::dec; + return _out; +} + +inline bool isLeaf(RLP const& _twoItem) +{ + assert(_twoItem.isList() && _twoItem.itemCount() == 2); + auto pl = _twoItem[0].payload(); + return (pl[0] & 0x20) != 0; +} + +inline NibbleSlice keyOf(bytesConstRef _hpe) +{ + if (!_hpe.size()) + return NibbleSlice(_hpe, 0); + if (_hpe[0] & 0x10) + return NibbleSlice(_hpe, 1); + else + return NibbleSlice(_hpe, 2); +} + +inline NibbleSlice keyOf(RLP const& _twoItem) +{ + return keyOf(_twoItem[0].payload()); +} + +byte uniqueInUse(RLP const& _orig, byte except); +std::string hexPrefixEncode(bytes const& _hexVector, bool _leaf = false, int _begin = 0, int _end = -1); +std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset); +std::string hexPrefixEncode(bytesConstRef _d1, unsigned _o1, bytesConstRef _d2, unsigned _o2, bool _leaf); + +inline std::string hexPrefixEncode(NibbleSlice _s, bool _leaf, int _begin = 0, int _end = -1) +{ + return hexPrefixEncode(_s.data, _leaf, _begin, _end, _s.offset); +} + +inline std::string hexPrefixEncode(NibbleSlice _s1, NibbleSlice _s2, bool _leaf) +{ + return hexPrefixEncode(_s1.data, _s1.offset, _s2.data, _s2.offset, _leaf); +} + +} diff --git a/src/eth_client/libdevcore/TrieDB.h b/src/eth_client/libdevcore/TrieDB.h new file mode 100644 index 0000000000..ac0b57e10f --- /dev/null +++ b/src/eth_client/libdevcore/TrieDB.h @@ -0,0 +1,1163 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include "Log.h" +#include "Exceptions.h" +#include "SHA3.h" +#include "TrieCommon.h" + +namespace dev +{ + +struct InvalidTrie: virtual dev::Exception {}; + +enum class Verification { + Skip, + Normal +}; + +/** + * @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree. + * This version uses a database backend. + * Usage: + * @code + * GenericTrieDB t(&myDB); + * assert(t.isNull()); + * t.init(); + * assert(t.isEmpty()); + * t.insert(x, y); + * assert(t.at(x) == y.toString()); + * t.remove(x); + * assert(t.isEmpty()); + * @endcode + */ +template +class GenericTrieDB +{ +public: + using DB = _DB; + + explicit GenericTrieDB(DB* _db = nullptr): m_db(_db) {} + GenericTrieDB(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { open(_db, _root, _v); } + ~GenericTrieDB() {} + + void open(DB* _db) { m_db = _db; } + void open(DB* _db, h256 const& _root, Verification _v = Verification::Normal) { m_db = _db; setRoot(_root, _v); } + + void init() { setRoot(forceInsertNode(&RLPNull)); assert(node(m_root).size()); } + + void setRoot(h256 const& _root, Verification _v = Verification::Normal) + { + m_root = _root; + if (_v == Verification::Normal) + { + if (m_root == EmptyTrie && !m_db->exists(m_root)) + init(); + } + if (_v == Verification::Normal) + if (!node(m_root).size()) + BOOST_THROW_EXCEPTION(RootNotFound()); + } + + /// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node). + bool isNull() const { return !node(m_root).size(); } + /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). + bool isEmpty() const { return m_root == EmptyTrie && node(m_root).size(); } + + h256 const& root() const + { + if (node(m_root).empty()) + BOOST_THROW_EXCEPTION(BadRoot() << errinfo_hash256(m_root)); + return m_root; + } // patch the root in the case of the empty trie. TODO: handle this properly. + + std::string at(bytes const& _key) const { return at(&_key); } + std::string at(bytesConstRef _key) const; + void insert(bytes const& _key, bytes const& _value) { insert(&_key, &_value); } + void insert(bytesConstRef _key, bytes const& _value) { insert(_key, &_value); } + void insert(bytes const& _key, bytesConstRef _value) { insert(&_key, _value); } + void insert(bytesConstRef _key, bytesConstRef _value); + void remove(bytes const& _key) { remove(&_key); } + void remove(bytesConstRef _key); + bool contains(bytes const& _key) const { return contains(&_key); } + bool contains(bytesConstRef _key) const { return !at(_key).empty(); } + + class iterator + { + public: + using value_type = std::pair; + + iterator() {} + explicit iterator(GenericTrieDB const* _db); + iterator(GenericTrieDB const* _db, bytesConstRef _key); + + iterator& operator++() { next(); return *this; } + + value_type operator*() const { return at(); } + value_type operator->() const { return at(); } + + bool operator==(iterator const& _c) const { return _c.m_trail == m_trail; } + bool operator!=(iterator const& _c) const { return _c.m_trail != m_trail; } + + value_type at() const; + + private: + void next(); + void next(NibbleSlice _key); + + struct Node + { + std::string rlp; + std::string key; // as hexPrefixEncoding. + byte child; // 255 -> entering, 16 -> actually at the node, 17 -> exiting, 0-15 -> actual children. + + // 255 -> 16 -> 0 -> 1 -> ... -> 15 -> 17 + + void setChild(unsigned _i) { child = _i; } + void setFirstChild() { child = 16; } + void incrementChild() { child = child == 16 ? 0 : child == 15 ? 17 : (child + 1); } + + bool operator==(Node const& _c) const { return rlp == _c.rlp && key == _c.key && child == _c.child; } + bool operator!=(Node const& _c) const { return !operator==(_c); } + }; + + protected: + std::vector m_trail; + GenericTrieDB const* m_that; + }; + + iterator begin() const { return iterator(this); } + iterator end() const { return iterator(); } + + iterator lower_bound(bytesConstRef _key) const { return iterator(this, _key); } + + /// Used for debugging, scans the whole trie. + void descendKey(h256 const& _k, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent = 0) const + { + _keyMask.erase(_k); + if (_k == m_root && _k == EmptyTrie) // root allowed to be empty + return; + std::string const s = node(_k); + RLP r = RLP(s); + descendList(r, _keyMask, _wasExt, _out, _indent); // if not, it must be a list + } + + /// Used for debugging, scans the whole trie. + void descendEntry( + RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const + { + if (_r.isData() && _r.size() == 32) + descendKey(_r.toHash(), _keyMask, _wasExt, _out, _indent); + else if (_r.isList()) + descendList(_r, _keyMask, _wasExt, _out, _indent); + else + BOOST_THROW_EXCEPTION(InvalidTrie()); + } + + /// Used for debugging, scans the whole trie. + void descendList(RLP const& _r, h256Hash& _keyMask, bool _wasExt, std::ostream* _out, int _indent) const + { + if (_r.isList() && _r.itemCount() == 2 && (!_wasExt || _out)) + { + if (_out) + (*_out) << std::string(_indent * 2, ' ') << (_wasExt ? "!2 " : "2 ") << sha3(_r.data()) << ": " << _r << "\n"; + if (!isLeaf(_r)) // don't go down leaves + descendEntry(_r[1], _keyMask, true, _out, _indent + 1); + } + else if (_r.isList() && _r.itemCount() == 17) + { + if (_out) + (*_out) << std::string(_indent * 2, ' ') << "17 " << sha3(_r.data()) << ": " << _r << "\n"; + for (unsigned i = 0; i < 16; ++i) + if (!_r[i].isEmpty()) // 16 branches are allowed to be empty + descendEntry(_r[i], _keyMask, false, _out, _indent + 1); + } + else + BOOST_THROW_EXCEPTION(InvalidTrie()); + } + + /// Used for debugging, scans the whole trie. + h256Hash leftOvers(std::ostream* _out = nullptr) const + { + h256Hash k = m_db->keys(); + descendKey(m_root, k, false, _out); + return k; + } + + /// Used for debugging, scans the whole trie. + void debugStructure(std::ostream& _out) const + { + leftOvers(&_out); + } + + /// Used for debugging, scans the whole trie. + /// @param _requireNoLeftOvers if true, requires that all keys are reachable. + bool check(bool _requireNoLeftOvers) const + { + try + { + return leftOvers().empty() || !_requireNoLeftOvers; + } + catch (...) + { + cwarn << boost::current_exception_diagnostic_information(); + return false; + } + } + + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } + +private: + RLPStream& streamNode(RLPStream& _s, bytes const& _b); + + std::string atAux(RLP const& _here, NibbleSlice _key) const; + + void mergeAtAux(RLPStream& _out, RLP const& _replace, NibbleSlice _key, bytesConstRef _value); + bytes mergeAt(RLP const& _replace, NibbleSlice _k, bytesConstRef _v, bool _inLine = false); + bytes mergeAt(RLP const& _replace, h256 const& _replaceHash, NibbleSlice _k, bytesConstRef _v, bool _inLine = false); + + bool deleteAtAux(RLPStream& _out, RLP const& _replace, NibbleSlice _key); + bytes deleteAt(RLP const& _replace, NibbleSlice _k); + + // in: null (DEL) -- OR -- [_k, V] (DEL) + // out: [_k, _s] + // -- OR -- + // in: [V0, ..., V15, S16] (DEL) AND _k == {} + // out: [V0, ..., V15, _s] + bytes place(RLP const& _orig, NibbleSlice _k, bytesConstRef _s); + + // in: [K, S] (DEL) + // out: null + // -- OR -- + // in: [V0, ..., V15, S] (DEL) + // out: [V0, ..., V15, null] + bytes remove(RLP const& _orig); + + // in: [K1 & K2, V] (DEL) : nibbles(K1) == _s, 0 < _s <= nibbles(K1 & K2) + // out: [K1, H] ; [K2, V] => H (INS) (being [K1, [K2, V]] if necessary) + bytes cleve(RLP const& _orig, unsigned _s); + + // in: [K1, H] (DEL) ; H <= [K2, V] (DEL) (being [K1, [K2, V]] (DEL) if necessary) + // out: [K1 & K2, V] + bytes graft(RLP const& _orig); + + // in: [V0, ... V15, S] (DEL) + // out1: [k{i}, Vi] where i < 16 + // out2: [k{}, S] where i == 16 + bytes merge(RLP const& _orig, byte _i); + + // in: [k{}, S] (DEL) + // out: [null ** 16, S] + // -- OR -- + // in: [k{i}, N] (DEL) + // out: [null ** i, N, null ** (16 - i)] + // -- OR -- + // in: [k{i}K, V] (DEL) + // out: [null ** i, H, null ** (16 - i)] ; [K, V] => H (INS) (being [null ** i, [K, V], null ** (16 - i)] if necessary) + bytes branch(RLP const& _orig); + + bool isTwoItemNode(RLP const& _n) const; + std::string deref(RLP const& _n) const; + + std::string node(h256 const& _h) const { return m_db->lookup(_h); } + + // These are low-level node insertion functions that just go straight through into the DB. + h256 forceInsertNode(bytesConstRef _v) { auto h = sha3(_v); forceInsertNode(h, _v); return h; } + void forceInsertNode(h256 const& _h, bytesConstRef _v) { m_db->insert(_h, _v); } + void forceKillNode(h256 const& _h) { m_db->kill(_h); } + + // This are semantically-aware node insertion functions that only kills when the node's + // data is < 32 bytes. It can safely be used when pruning the trie but won't work correctly + // for the special case of the root (which is always looked up via a hash). In that case, + // use forceKillNode(). + void killNode(RLP const& _d) { if (_d.data().size() >= 32) forceKillNode(sha3(_d.data())); } + void killNode(RLP const& _d, h256 const& _h) { if (_d.data().size() >= 32) forceKillNode(_h); } + + h256 m_root; + DB* m_db = nullptr; +}; + +template +std::ostream& operator<<(std::ostream& _out, GenericTrieDB const& _db) +{ + for (auto const& i: _db) + _out << escaped(i.first.toString(), false) << ": " << escaped(i.second.toString(), false) << std::endl; + return _out; +} + +/** + * Different view on a GenericTrieDB that can use different key types. + */ +template +class SpecificTrieDB: public Generic +{ +public: + using DB = typename Generic::DB; + using KeyType = _KeyType; + + SpecificTrieDB(DB* _db = nullptr): Generic(_db) {} + SpecificTrieDB(DB* _db, h256 _root, Verification _v = Verification::Normal): Generic(_db, _root, _v) {} + + std::string operator[](KeyType _k) const { return at(_k); } + + bool contains(KeyType _k) const { return Generic::contains(bytesConstRef((byte const*)&_k, sizeof(KeyType))); } + std::string at(KeyType _k) const { return Generic::at(bytesConstRef((byte const*)&_k, sizeof(KeyType))); } + void insert(KeyType _k, bytesConstRef _value) { Generic::insert(bytesConstRef((byte const*)&_k, sizeof(KeyType)), _value); } + void insert(KeyType _k, bytes const& _value) { insert(_k, bytesConstRef(&_value)); } + void remove(KeyType _k) { Generic::remove(bytesConstRef((byte const*)&_k, sizeof(KeyType))); } + + class iterator: public Generic::iterator + { + public: + using Super = typename Generic::iterator; + using value_type = std::pair; + + iterator() {} + iterator(Generic const* _db): Super(_db) {} + iterator(Generic const* _db, bytesConstRef _k): Super(_db, _k) {} + + value_type operator*() const { return at(); } + value_type operator->() const { return at(); } + + value_type at() const; + }; + + iterator begin() const { return this; } + iterator end() const { return iterator(); } + iterator lower_bound(KeyType _k) const { return iterator(this, bytesConstRef((byte const*)&_k, sizeof(KeyType))); } +}; + +template +std::ostream& operator<<(std::ostream& _out, SpecificTrieDB const& _db) +{ + for (auto const& i: _db) + _out << i.first << ": " << escaped(i.second.toString(), false) << std::endl; + return _out; +} + +template +class HashedGenericTrieDB: private SpecificTrieDB, h256> +{ + using Super = SpecificTrieDB, h256>; + +public: + using DB = _DB; + + HashedGenericTrieDB(DB* _db = nullptr): Super(_db) {} + HashedGenericTrieDB(DB* _db, h256 _root, Verification _v = Verification::Normal): Super(_db, _root, _v) {} + + using Super::open; + using Super::init; + using Super::setRoot; + + /// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node). + using Super::isNull; + /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). + using Super::isEmpty; + + using Super::root; + using Super::db; + + using Super::leftOvers; + using Super::check; + using Super::debugStructure; + + std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } + bool contains(bytesConstRef _key) const { return Super::contains(sha3(_key)); } + void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(sha3(_key), _value); } + void remove(bytesConstRef _key) { Super::remove(sha3(_key)); } + + // empty from the PoV of the iterator interface; still need a basic iterator impl though. + class iterator + { + public: + using value_type = std::pair; + + iterator() {} + iterator(HashedGenericTrieDB const*) {} + iterator(HashedGenericTrieDB const*, bytesConstRef) {} + + iterator& operator++() { return *this; } + value_type operator*() const { return value_type(); } + value_type operator->() const { return value_type(); } + + bool operator==(iterator const&) const { return true; } + bool operator!=(iterator const&) const { return false; } + + value_type at() const { return value_type(); } + }; + iterator begin() const { return iterator(); } + iterator end() const { return iterator(); } + iterator lower_bound(bytesConstRef) const { return iterator(); } +}; + +// Hashed & Hash-key mapping +template +class FatGenericTrieDB: private SpecificTrieDB, h256> +{ + using Super = SpecificTrieDB, h256>; + +public: + using DB = _DB; + FatGenericTrieDB(DB* _db = nullptr): Super(_db) {} + FatGenericTrieDB(DB* _db, h256 _root, Verification _v = Verification::Normal): Super(_db, _root, _v) {} + + using Super::init; + using Super::isNull; + using Super::isEmpty; + using Super::root; + using Super::leftOvers; + using Super::check; + using Super::open; + using Super::setRoot; + using Super::db; + using Super::debugStructure; + + std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } + bool contains(bytesConstRef _key) const { return Super::contains(sha3(_key)); } + void insert(bytesConstRef _key, bytesConstRef _value) + { + h256 hash = sha3(_key); + Super::insert(hash, _value); + Super::db()->insertAux(hash, _key); + } + + void remove(bytesConstRef _key) { Super::remove(sha3(_key)); } + + // iterates over pairs + class iterator: public GenericTrieDB<_DB>::iterator + { + public: + using Super = typename GenericTrieDB<_DB>::iterator; + + iterator() { } + iterator(FatGenericTrieDB const* _trie) : Super(_trie) { } + + typename Super::value_type at() const + { + auto hashed = Super::at(); + m_key = static_cast(Super::m_that)->db()->lookupAux(h256(hashed.first)); + return std::make_pair(&m_key, std::move(hashed.second)); + } + + private: + mutable bytes m_key; + }; + + iterator begin() const { return iterator(); } + iterator end() const { return iterator(); } + + // iterates over pairs + class HashedIterator: public GenericTrieDB<_DB>::iterator + { + public: + using Super = typename GenericTrieDB<_DB>::iterator; + + HashedIterator() {} + HashedIterator(FatGenericTrieDB const* _trie) : Super(_trie) {} + HashedIterator(FatGenericTrieDB const* _trie, bytesConstRef _hashedKey): Super(_trie, _hashedKey) {} + + bytes key() const + { + auto hashed = Super::at(); + return static_cast(Super::m_that)->db()->lookupAux(h256(hashed.first)); + } + }; + + HashedIterator hashedBegin() const { return HashedIterator(this); } + HashedIterator hashedEnd() const { return HashedIterator(); } + HashedIterator hashedLowerBound(h256 const& _hashedKey) const { return HashedIterator(this, _hashedKey.ref()); } +}; + +template using TrieDB = SpecificTrieDB, KeyType>; + +} + +// Template implementations... +namespace dev +{ + +template GenericTrieDB::iterator::iterator(GenericTrieDB const* _db) +{ + m_that = _db; + m_trail.push_back({_db->node(_db->m_root), std::string(1, '\0'), 255}); // one null byte is the HPE for the empty key. + next(); +} + +template GenericTrieDB::iterator::iterator(GenericTrieDB const* _db, bytesConstRef _fullKey) +{ + m_that = _db; + m_trail.push_back({_db->node(_db->m_root), std::string(1, '\0'), 255}); // one null byte is the HPE for the empty key. + next(_fullKey); +} + +template typename GenericTrieDB::iterator::value_type GenericTrieDB::iterator::at() const +{ + assert(m_trail.size()); + Node const& b = m_trail.back(); + assert(b.key.size()); + assert(!(b.key[0] & 0x10)); // should be an integer number of bytes (i.e. not an odd number of nibbles). + + RLP rlp(b.rlp); + return std::make_pair(bytesConstRef(b.key).cropped(1), rlp[rlp.itemCount() == 2 ? 1 : 16].payload()); +} + +template void GenericTrieDB::iterator::next(NibbleSlice _key) +{ + NibbleSlice k = _key; + while (true) + { + if (m_trail.empty()) + { + m_that = nullptr; + return; + } + + Node const& b = m_trail.back(); + RLP rlp(b.rlp); + + if (m_trail.back().child == 255) + { + // Entering. Look for first... + if (rlp.isEmpty()) + { + // Kill our search as soon as we hit an empty node. + k.clear(); + m_trail.pop_back(); + continue; + } + if (!rlp.isList() || (rlp.itemCount() != 2 && rlp.itemCount() != 17)) + { + m_that = nullptr; + return; + } + if (rlp.itemCount() == 2) + { + // Just turn it into a valid Branch + auto keyOfRLP = keyOf(rlp); + + // TODO: do something different depending on how keyOfRLP compares to k.mid(0, std::min(k.size(), keyOfRLP.size())); + // if == all is good - continue descent. + // if > discard key and continue descent. + // if < discard key and skip node. + + if (!k.contains(keyOfRLP)) + { + if (!k.isEarlierThan(keyOfRLP)) + { + k.clear(); + m_trail.pop_back(); + continue; + } + k.clear(); + } + + k = k.mid(std::min(k.size(), keyOfRLP.size())); + m_trail.back().key = hexPrefixEncode(keyOf(m_trail.back().key), keyOfRLP, false); + if (isLeaf(rlp)) + { + // leaf - exit now. + if (k.empty()) + { + m_trail.back().child = 0; + return; + } + // Still data in key we're supposed to be looking for when we're at a leaf. Go for next one. + k.clear(); + m_trail.pop_back(); + continue; + } + + // enter child. + m_trail.back().rlp = m_that->deref(rlp[1]); + // no need to set .child as 255 - it's already done. + continue; + } + else + { + // Already a branch - look for first valid. + if (k.size()) + { + m_trail.back().setChild(k[0]); + k = k.mid(1); + } + else + m_trail.back().setChild(16); + // run through to... + } + } + else + { + // Continuing/exiting. Look for next... + if (!(rlp.isList() && rlp.itemCount() == 17)) + { + k.clear(); + m_trail.pop_back(); + continue; + } + // else run through to... + m_trail.back().incrementChild(); + } + + // ...here. should only get here if we're a list. + assert(rlp.isList() && rlp.itemCount() == 17); + for (;; m_trail.back().incrementChild()) + if (m_trail.back().child == 17) + { + // finished here. + k.clear(); + m_trail.pop_back(); + break; + } + else if (!rlp[m_trail.back().child].isEmpty()) + { + if (m_trail.back().child == 16) + return; // have a value at this node - exit now. + else + { + // lead-on to another node - enter child. + // fixed so that Node passed into push_back is constructed *before* m_trail is potentially resized (which invalidates back and rlp) + Node const& back = m_trail.back(); + m_trail.push_back(Node{ + m_that->deref(rlp[back.child]), + hexPrefixEncode(keyOf(back.key), NibbleSlice(bytesConstRef(&back.child, 1), 1), false), + 255 + }); + break; + } + } + else + k.clear(); + } +} + +template void GenericTrieDB::iterator::next() +{ + while (true) + { + if (m_trail.empty()) + { + m_that = nullptr; + return; + } + + Node const& b = m_trail.back(); + RLP rlp(b.rlp); + + if (m_trail.back().child == 255) + { + // Entering. Look for first... + if (rlp.isEmpty()) + { + m_trail.pop_back(); + continue; + } + if (!(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17))) + { + m_that = nullptr; + return; + } + if (rlp.itemCount() == 2) + { + // Just turn it into a valid Branch + m_trail.back().key = hexPrefixEncode(keyOf(m_trail.back().key), keyOf(rlp), false); + if (isLeaf(rlp)) + { + // leaf - exit now. + m_trail.back().child = 0; + return; + } + + // enter child. + m_trail.back().rlp = m_that->deref(rlp[1]); + // no need to set .child as 255 - it's already done. + continue; + } + else + { + // Already a branch - look for first valid. + m_trail.back().setFirstChild(); + // run through to... + } + } + else + { + // Continuing/exiting. Look for next... + if (!(rlp.isList() && rlp.itemCount() == 17)) + { + m_trail.pop_back(); + continue; + } + // else run through to... + m_trail.back().incrementChild(); + } + + // ...here. should only get here if we're a list. + assert(rlp.isList() && rlp.itemCount() == 17); + for (;; m_trail.back().incrementChild()) + if (m_trail.back().child == 17) + { + // finished here. + m_trail.pop_back(); + break; + } + else if (!rlp[m_trail.back().child].isEmpty()) + { + if (m_trail.back().child == 16) + return; // have a value at this node - exit now. + else + { + // lead-on to another node - enter child. + // fixed so that Node passed into push_back is constructed *before* m_trail is potentially resized (which invalidates back and rlp) + Node const& back = m_trail.back(); + m_trail.push_back(Node{ + m_that->deref(rlp[back.child]), + hexPrefixEncode(keyOf(back.key), NibbleSlice(bytesConstRef(&back.child, 1), 1), false), + 255 + }); + break; + } + } + } +} + +template typename SpecificTrieDB::iterator::value_type SpecificTrieDB::iterator::at() const +{ + auto p = Super::at(); + value_type ret; + assert(p.first.size() == sizeof(KeyType)); + memcpy(&ret.first, p.first.data(), sizeof(KeyType)); + ret.second = p.second; + return ret; +} + +template void GenericTrieDB::insert(bytesConstRef _key, bytesConstRef _value) +{ + std::string rootValue = node(m_root); + assert(rootValue.size()); + bytes b = mergeAt(RLP(rootValue), m_root, NibbleSlice(_key), _value); + + // mergeAt won't attempt to delete the node if it's less than 32 bytes + // However, we know it's the root node and thus always hashed. + // So, if it's less than 32 (and thus should have been deleted but wasn't) then we delete it here. + if (rootValue.size() < 32) + forceKillNode(m_root); + m_root = forceInsertNode(&b); +} + +template std::string GenericTrieDB::at(bytesConstRef _key) const +{ + return atAux(RLP(node(m_root)), _key); +} + +template std::string GenericTrieDB::atAux(RLP const& _here, NibbleSlice _key) const +{ + if (_here.isEmpty() || _here.isNull()) + // not found. + return std::string(); + unsigned itemCount = _here.itemCount(); + assert(_here.isList() && (itemCount == 2 || itemCount == 17)); + if (itemCount == 2) + { + auto k = keyOf(_here); + if (_key == k && isLeaf(_here)) + // reached leaf and it's us + return _here[1].toString(); + else if (_key.contains(k) && !isLeaf(_here)) + // not yet at leaf and it might yet be us. onwards... + return atAux(_here[1].isList() ? _here[1] : RLP(node(_here[1].toHash())), _key.mid(k.size())); + else + // not us. + return std::string(); + } + else + { + if (_key.size() == 0) + return _here[16].toString(); + auto n = _here[_key[0]]; + if (n.isEmpty()) + return std::string(); + else + return atAux(n.isList() ? n : RLP(node(n.toHash())), _key.mid(1)); + } +} + +template bytes GenericTrieDB::mergeAt(RLP const& _orig, NibbleSlice _k, bytesConstRef _v, bool _inLine) +{ + return mergeAt(_orig, sha3(_orig.data()), _k, _v, _inLine); +} + +template bytes GenericTrieDB::mergeAt(RLP const& _orig, h256 const& _origHash, NibbleSlice _k, bytesConstRef _v, bool _inLine) +{ + // The caller will make sure that the bytes are inserted properly. + // - This might mean inserting an entry into m_over + // We will take care to ensure that (our reference to) _orig is killed. + + // Empty - just insert here + if (_orig.isEmpty()) + return place(_orig, _k, _v); + + unsigned itemCount = _orig.itemCount(); + assert(_orig.isList() && (itemCount == 2 || itemCount == 17)); + if (itemCount == 2) + { + // pair... + NibbleSlice k = keyOf(_orig); + + // exactly our node - place value in directly. + if (k == _k && isLeaf(_orig)) + return place(_orig, _k, _v); + + // partial key is our key - move down. + if (_k.contains(k) && !isLeaf(_orig)) + { + if (!_inLine) + killNode(_orig, _origHash); + RLPStream s(2); + s.append(_orig[0]); + mergeAtAux(s, _orig[1], _k.mid(k.size()), _v); + return s.out(); + } + + auto sh = _k.shared(k); +// std::cout << _k << " sh " << k << " = " << sh << std::endl; + if (sh) + { + // shared stuff - cleve at disagreement. + auto cleved = cleve(_orig, sh); + return mergeAt(RLP(cleved), _k, _v, true); + } + else + { + // nothing shared - branch + auto branched = branch(_orig); + return mergeAt(RLP(branched), _k, _v, true); + } + } + else + { + // branch... + + // exactly our node - place value. + if (_k.size() == 0) + return place(_orig, _k, _v); + + // Kill the node. + if (!_inLine) + killNode(_orig, _origHash); + + // not exactly our node - delve to next level at the correct index. + byte n = _k[0]; + RLPStream r(17); + for (byte i = 0; i < 17; ++i) + if (i == n) + mergeAtAux(r, _orig[i], _k.mid(1), _v); + else + r.append(_orig[i]); + return r.out(); + } + +} + +template void GenericTrieDB::mergeAtAux(RLPStream& _out, RLP const& _orig, NibbleSlice _k, bytesConstRef _v) +{ + RLP r = _orig; + std::string s; + // _orig is always a segment of a node's RLP - removing it alone is pointless. However, if may be a hash, in which case we deref and we know it is removable. + bool isRemovable = false; + if (!r.isList() && !r.isEmpty()) + { + h256 h = _orig.toHash(); + // std::cerr << "going down non-inline node " << h << "\n"; + s = node(h); + r = RLP(s); + assert(!r.isNull()); + isRemovable = true; + } + bytes b = mergeAt(r, _k, _v, !isRemovable); + streamNode(_out, b); +} + +template void GenericTrieDB::remove(bytesConstRef _key) +{ + std::string rv = node(m_root); + bytes b = deleteAt(RLP(rv), NibbleSlice(_key)); + if (b.size()) + { + if (rv.size() < 32) + forceKillNode(m_root); + m_root = forceInsertNode(&b); + } +} + +template bool GenericTrieDB::isTwoItemNode(RLP const& _n) const +{ + return (_n.isData() && RLP(node(_n.toHash())).itemCount() == 2) + || (_n.isList() && _n.itemCount() == 2); +} + +template std::string GenericTrieDB::deref(RLP const& _n) const +{ + return _n.isList() ? _n.data().toString() : node(_n.toHash()); +} + +template bytes GenericTrieDB::deleteAt(RLP const& _orig, NibbleSlice _k) +{ + // The caller will make sure that the bytes are inserted properly. + // - This might mean inserting an entry into m_over + // We will take care to ensure that (our reference to) _orig is killed. + + // Empty - not found - no change. + if (_orig.isEmpty()) + return bytes(); + + assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17)); + if (_orig.itemCount() == 2) + { + // pair... + NibbleSlice k = keyOf(_orig); + + // exactly our node - return null. + if (k == _k && isLeaf(_orig)) + { + killNode(_orig); + return RLPNull; + } + + // partial key is our key - move down. + if (_k.contains(k)) + { + RLPStream s; + s.appendList(2) << _orig[0]; + if (!deleteAtAux(s, _orig[1], _k.mid(k.size()))) + return bytes(); + killNode(_orig); + RLP r(s.out()); + if (isTwoItemNode(r[1])) + return graft(r); + return s.out(); + } + else + // not found - no change. + return bytes(); + } + else + { + // branch... + + // exactly our node - remove and rejig. + if (_k.size() == 0 && !_orig[16].isEmpty()) + { + // Kill the node. + killNode(_orig); + + byte used = uniqueInUse(_orig, 16); + if (used != 255) + if (isTwoItemNode(_orig[used])) + { + auto merged = merge(_orig, used); + return graft(RLP(merged)); + } + else + return merge(_orig, used); + else + { + RLPStream r(17); + for (byte i = 0; i < 16; ++i) + r << _orig[i]; + r << ""; + return r.out(); + } + } + else + { + // not exactly our node - delve to next level at the correct index. + RLPStream r(17); + byte n = _k[0]; + for (byte i = 0; i < 17; ++i) + if (i == n) + { + if (!deleteAtAux(r, _orig[i], _k.mid(1))) // bomb out if the key didn't turn up. + return bytes(); + } + else + r << _orig[i]; + + // Kill the node. + killNode(_orig); + + // check if we ended up leaving the node invalid. + RLP rlp(r.out()); + byte used = uniqueInUse(rlp, 255); + if (used == 255) // no - all ok. + return r.out(); + + // yes; merge + if (isTwoItemNode(rlp[used])) + { + auto merged = merge(rlp, used); + return graft(RLP(merged)); + } + else + return merge(rlp, used); + } + } + +} + +template bool GenericTrieDB::deleteAtAux(RLPStream& _out, RLP const& _orig, NibbleSlice _k) +{ + + bytes b = _orig.isEmpty() ? bytes() : deleteAt(_orig.isList() ? _orig : RLP(node(_orig.toHash())), _k); + + if (!b.size()) // not found - no change. + return false; + +/* if (_orig.isList()) + killNode(_orig); + else + killNode(_orig.toHash());*/ + + streamNode(_out, b); + return true; +} + +template bytes GenericTrieDB::place(RLP const& _orig, NibbleSlice _k, bytesConstRef _s) +{ + killNode(_orig); + if (_orig.isEmpty()) + return rlpList(hexPrefixEncode(_k, true), _s); + + assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17)); + if (_orig.itemCount() == 2) + return rlpList(_orig[0], _s); + + auto s = RLPStream(17); + for (unsigned i = 0; i < 16; ++i) + s << _orig[i]; + s << _s; + return s.out(); +} + +// in1: [K, S] (DEL) +// out1: null +// in2: [V0, ..., V15, S] (DEL) +// out2: [V0, ..., V15, null] iff exists i: !!Vi -- OR -- null otherwise +template bytes GenericTrieDB::remove(RLP const& _orig) +{ + killNode(_orig); + + assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17)); + if (_orig.itemCount() == 2) + return RLPNull; + RLPStream r(17); + for (unsigned i = 0; i < 16; ++i) + r << _orig[i]; + r << ""; + return r.out(); +} + +template RLPStream& GenericTrieDB::streamNode(RLPStream& _s, bytes const& _b) +{ + if (_b.size() < 32) + _s.appendRaw(_b); + else + _s.append(forceInsertNode(&_b)); + return _s; +} + +template bytes GenericTrieDB::cleve(RLP const& _orig, unsigned _s) +{ + killNode(_orig); + assert(_orig.isList() && _orig.itemCount() == 2); + auto k = keyOf(_orig); + assert(_s && _s <= k.size()); + + RLPStream bottom(2); + bottom << hexPrefixEncode(k, isLeaf(_orig), /*ugh*/(int)_s) << _orig[1]; + + RLPStream top(2); + top << hexPrefixEncode(k, false, 0, /*ugh*/(int)_s); + streamNode(top, bottom.out()); + + return top.out(); +} + +template bytes GenericTrieDB::graft(RLP const& _orig) +{ + assert(_orig.isList() && _orig.itemCount() == 2); + std::string s; + RLP n; + if (_orig[1].isList()) + n = _orig[1]; + else + { + // remove second item from the trie after derefrencing it into s & n. + auto lh = _orig[1].toHash(); + s = node(lh); + forceKillNode(lh); + n = RLP(s); + } + assert(n.itemCount() == 2); + + return rlpList(hexPrefixEncode(keyOf(_orig), keyOf(n), isLeaf(n)), n[1]); +// auto ret = +// std::cout << keyOf(_orig) << " ++ " << keyOf(n) << " == " << keyOf(RLP(ret)) << std::endl; +// return ret; +} + +template bytes GenericTrieDB::merge(RLP const& _orig, byte _i) +{ + assert(_orig.isList() && _orig.itemCount() == 17); + RLPStream s(2); + if (_i != 16) + { + assert(!_orig[_i].isEmpty()); + s << hexPrefixEncode(bytesConstRef(&_i, 1), false, 1, 2, 0); + } + else + s << hexPrefixEncode(bytes(), true); + s << _orig[_i]; + return s.out(); +} + +template bytes GenericTrieDB::branch(RLP const& _orig) +{ + assert(_orig.isList() && _orig.itemCount() == 2); + killNode(_orig); + + auto k = keyOf(_orig); + RLPStream r(17); + if (k.size() == 0) + { + assert(isLeaf(_orig)); + for (unsigned i = 0; i < 16; ++i) + r << ""; + r << _orig[1]; + } + else + { + byte b = k[0]; + for (unsigned i = 0; i < 16; ++i) + if (i == b) + if (isLeaf(_orig) || k.size() > 1) + streamNode(r, rlpList(hexPrefixEncode(k.mid(1), isLeaf(_orig)), _orig[1])); + else + r << _orig[1]; + else + r << ""; + r << ""; + } + return r.out(); +} + +} diff --git a/src/eth_client/libdevcore/TrieHash.cpp b/src/eth_client/libdevcore/TrieHash.cpp new file mode 100644 index 0000000000..34d3cd79f0 --- /dev/null +++ b/src/eth_client/libdevcore/TrieHash.cpp @@ -0,0 +1,117 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "TrieHash.h" +#include "TrieCommon.h" +#include "TrieDB.h" // @TODO replace ASAP! + +namespace dev +{ + +void hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen, RLPStream& _rlp); + +void hash256rlp(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen, RLPStream& _rlp) +{ + if (_begin == _end) + _rlp << ""; // NULL + else if (std::next(_begin) == _end) + { + // only one left - terminate with the pair. + _rlp.appendList(2) << hexPrefixEncode(_begin->first, true, _preLen) << _begin->second; + } + else + { + // find the number of common prefix nibbles shared + // i.e. the minimum number of nibbles shared at the beginning between the first hex string and each successive. + unsigned sharedPre = (unsigned)-1; + unsigned c = 0; + for (auto i = std::next(_begin); i != _end && sharedPre; ++i, ++c) + { + unsigned x = std::min(sharedPre, std::min((unsigned)_begin->first.size(), (unsigned)i->first.size())); + unsigned shared = _preLen; + for (; shared < x && _begin->first[shared] == i->first[shared]; ++shared) {} + sharedPre = std::min(shared, sharedPre); + } + if (sharedPre > _preLen) + { + // if they all have the same next nibble, we also want a pair. + _rlp.appendList(2) << hexPrefixEncode(_begin->first, false, _preLen, (int)sharedPre); + hash256aux(_s, _begin, _end, (unsigned)sharedPre, _rlp); + } + else + { + // otherwise enumerate all 16+1 entries. + _rlp.appendList(17); + auto b = _begin; + if (_preLen == b->first.size()) + ++b; + for (auto i = 0; i < 16; ++i) + { + auto n = b; + for (; n != _end && n->first[_preLen] == i; ++n) {} + if (b == n) + _rlp << ""; + else + hash256aux(_s, b, n, _preLen + 1, _rlp); + b = n; + } + if (_preLen == _begin->first.size()) + _rlp << _begin->second; + else + _rlp << ""; + + } + } +} + +void hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen, RLPStream& _rlp) +{ + RLPStream rlp; + hash256rlp(_s, _begin, _end, _preLen, rlp); + if (rlp.out().size() < 32) + { + // RECURSIVE RLP + _rlp.appendRaw(rlp.out()); + } + else + _rlp << sha3(rlp.out()); +} + +bytes rlp256(BytesMap const& _s) +{ + // build patricia tree. + if (_s.empty()) + return rlp(""); + HexMap hexMap; + for (auto i = _s.rbegin(); i != _s.rend(); ++i) + hexMap[asNibbles(bytesConstRef(&i->first))] = i->second; + RLPStream s; + hash256rlp(hexMap, hexMap.cbegin(), hexMap.cend(), 0, s); + return s.out(); +} + +h256 hash256(BytesMap const& _s) +{ + return sha3(rlp256(_s)); +} + +h256 orderedTrieRoot(std::vector const& _data) +{ + BytesMap m; + unsigned j = 0; + for (auto i: _data) + m[rlp(j++)] = i; + return hash256(m); +} + +h256 orderedTrieRoot(std::vector const& _data) +{ + BytesMap m; + unsigned j = 0; + for (auto i: _data) + m[rlp(j++)] = i.toBytes(); + return hash256(m); +} + +} diff --git a/src/eth_client/libdevcore/TrieHash.h b/src/eth_client/libdevcore/TrieHash.h new file mode 100644 index 0000000000..82f574fb6c --- /dev/null +++ b/src/eth_client/libdevcore/TrieHash.h @@ -0,0 +1,28 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include + +#include + +namespace dev +{ + +bytes rlp256(BytesMap const& _s); +h256 hash256(BytesMap const& _s); + +template inline h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue) +{ + BytesMap m; + for (unsigned i = 0; i < _itemCount; ++i) + m[_getKey(i)] = _getValue(i); + return hash256(m); +} + +h256 orderedTrieRoot(std::vector const& _data); +h256 orderedTrieRoot(std::vector const& _data); + +} diff --git a/src/eth_client/libdevcore/UndefMacros.h b/src/eth_client/libdevcore/UndefMacros.h new file mode 100644 index 0000000000..3150a8e9c9 --- /dev/null +++ b/src/eth_client/libdevcore/UndefMacros.h @@ -0,0 +1,30 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// This header should be used to #undef some really evil macros defined by +/// windows.h which result in conflict with our libsolidity/Token.h +#pragma once + +#if defined(_MSC_VER) || defined(__MINGW32__) + +#undef DELETE +#undef IN +#undef VOID +#undef THIS +#undef CONST + +// Conflicting define on MinGW in windows.h +// windows.h(19): #define interface struct +#ifdef interface +#undef interface +#endif + +#elif defined(DELETE) || defined(IN) || defined(VOID) || defined(THIS) || defined(CONST) || defined(interface) + +#error "The preceding macros in this header file are reserved for V8's "\ +"TOKEN_LIST. Please add a platform specific define above to undefine "\ +"overlapping macros." + +#endif diff --git a/src/eth_client/libdevcore/db.h b/src/eth_client/libdevcore/db.h new file mode 100644 index 0000000000..fddaf3d8d9 --- /dev/null +++ b/src/eth_client/libdevcore/db.h @@ -0,0 +1,73 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "Exceptions.h" +#include "dbfwd.h" + +#include +#include + +namespace dev +{ +namespace db +{ +// WriteBatchFace implements database write batch for a specific concrete +// database implementation. +class WriteBatchFace +{ +public: + virtual ~WriteBatchFace() = default; + + virtual void insert(Slice _key, Slice _value) = 0; + virtual void kill(Slice _key) = 0; + +protected: + WriteBatchFace() = default; + // Noncopyable + WriteBatchFace(WriteBatchFace const&) = delete; + WriteBatchFace& operator=(WriteBatchFace const&) = delete; + // Nonmovable + WriteBatchFace(WriteBatchFace&&) = delete; + WriteBatchFace& operator=(WriteBatchFace&&) = delete; +}; + +class DatabaseFace +{ +public: + virtual ~DatabaseFace() = default; + virtual std::string lookup(Slice _key) const = 0; + virtual bool exists(Slice _key) const = 0; + virtual void insert(Slice _key, Slice _value) = 0; + virtual void kill(Slice _key) = 0; + + virtual std::unique_ptr createWriteBatch() const = 0; + virtual void commit(std::unique_ptr _batch) = 0; + + // A database must implement the `forEach` method that allows the caller + // to pass in a function `f`, which will be called with the key and value + // of each record in the database. If `f` returns false, the `forEach` + // method must return immediately. + virtual void forEach(std::function f) const = 0; +}; + +DEV_SIMPLE_EXCEPTION(DatabaseError); + +enum class DatabaseStatus +{ + Ok, + NotFound, + Corruption, + NotSupported, + InvalidArgument, + IOError, + Unknown +}; + +using errinfo_dbStatusCode = boost::error_info; +using errinfo_dbStatusString = boost::error_info; + +} // namespace db +} // namespace dev diff --git a/src/eth_client/libdevcore/dbfwd.h b/src/eth_client/libdevcore/dbfwd.h new file mode 100644 index 0000000000..9e6b63fcaf --- /dev/null +++ b/src/eth_client/libdevcore/dbfwd.h @@ -0,0 +1,16 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#pragma once + +#include "vector_ref.h" + +namespace dev +{ +namespace db +{ +using Slice = vector_ref; +class WriteBatchFace; +class DatabaseFace; +} +} diff --git a/src/eth_client/libdevcore/vector_ref.h b/src/eth_client/libdevcore/vector_ref.h new file mode 100644 index 0000000000..35a9eff0b3 --- /dev/null +++ b/src/eth_client/libdevcore/vector_ref.h @@ -0,0 +1,117 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifdef __INTEL_COMPILER +#pragma warning(disable:597) //will not be called for implicit or explicit conversions +#endif + +namespace dev +{ + +/** + * A modifiable reference to an existing object or vector in memory. + */ +template +class vector_ref +{ +public: + using value_type = _T; + using element_type = _T; + using mutable_value_type = typename std::conditional::value, typename std::remove_const<_T>::type, _T>::type; + + static_assert(std::is_pod::value, "vector_ref can only be used with PODs due to its low-level treatment of data."); + + vector_ref(): m_data(nullptr), m_count(0) {} + /// Creates a new vector_ref to point to @a _count elements starting at @a _data. + vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} + /// Creates a new vector_ref pointing to the data part of a string (given as pointer). + vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {} + /// Creates a new vector_ref pointing to the data part of a vector (given as pointer). + vector_ref(typename std::conditional::value, std::vector::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} + /// Creates a new vector_ref pointing to the data part of a string (given as reference). + vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T)) {} + explicit operator bool() const { return m_data && m_count; } + + bool contentsEqual(std::vector const& _c) const { if (!m_data || m_count == 0) return _c.empty(); else return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count * sizeof(_T)); } + std::vector toVector() const { return std::vector(m_data, m_data + m_count); } + std::vector toBytes() const { return std::vector(reinterpret_cast(m_data), reinterpret_cast(m_data) + m_count * sizeof(_T)); } + std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); } + + template explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); } + operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } + + _T* data() const { return m_data; } + /// @returns the number of elements referenced (not necessarily number of bytes). + size_t count() const { return m_count; } + /// @returns the number of elements referenced (not necessarily number of bytes). + size_t size() const { return m_count; } + bool empty() const { return !m_count; } + /// @returns a new vector_ref pointing at the next chunk of @a size() elements. + vector_ref<_T> next() const { if (!m_data) return *this; else return vector_ref<_T>(m_data + m_count, m_count); } + /// @returns a new vector_ref which is a shifted and shortened view of the original data. + /// If this goes out of bounds in any way, returns an empty vector_ref. + /// If @a _count is ~size_t(0), extends the view to the end of the data. + vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin <= m_count && _count <= m_count && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); } + /// @returns a new vector_ref which is a shifted view of the original data (not going beyond it). + vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); } + void retarget(_T* _d, size_t _s) { m_data = _d; m_count = _s; } + void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); } + template bool overlapsWith(vector_ref _t) const { void const* f1 = data(); void const* t1 = data() + size(); void const* f2 = _t.data(); void const* t2 = _t.data() + _t.size(); return f1 < t2 && t1 > f2; } + /// Copies the contents of this vector_ref to the contents of @a _t, up to the max size of @a _t. + void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } + /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. + void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + /// Securely overwrite the memory. + /// @note adapted from OpenSSL's implementation. + void cleanse() + { + static std::atomic s_cleanseCounter{0u}; + uint8_t* p = (uint8_t*)begin(); + size_t const len = (uint8_t*)end() - p; + size_t loop = len; + size_t count = s_cleanseCounter; + while (loop--) + { + *(p++) = (uint8_t)count; + count += (17 + ((size_t)p & 0xf)); + } + p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len); + if (p) + count += (63 + (size_t)p); + s_cleanseCounter = (uint8_t)count; + memset((uint8_t*)begin(), 0, len); + } + + _T* begin() { return m_data; } + _T* end() { return m_data + m_count; } + _T const* begin() const { return m_data; } + _T const* end() const { return m_data + m_count; } + + _T& operator[](size_t _i) { assert(m_data); assert(_i < m_count); return m_data[_i]; } + _T const& operator[](size_t _i) const { assert(m_data); assert(_i < m_count); return m_data[_i]; } + + bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; } + bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); } + + void reset() { m_data = nullptr; m_count = 0; } + +private: + _T* m_data; + size_t m_count; +}; + +template vector_ref<_T const> ref(_T const& _t) { return vector_ref<_T const>(&_t, 1); } +template vector_ref<_T> ref(_T& _t) { return vector_ref<_T>(&_t, 1); } +template vector_ref<_T const> ref(std::vector<_T> const& _t) { return vector_ref<_T const>(&_t); } +template vector_ref<_T> ref(std::vector<_T>& _t) { return vector_ref<_T>(&_t); } + +} diff --git a/src/eth_client/libdevcrypto/Blake2.cpp b/src/eth_client/libdevcrypto/Blake2.cpp new file mode 100644 index 0000000000..55f8e2e258 --- /dev/null +++ b/src/eth_client/libdevcrypto/Blake2.cpp @@ -0,0 +1,160 @@ +/// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "Blake2.h" + +#include + +// The Blake 2 F compression function implemenation is based on the reference implementation, +// see https://github.com/BLAKE2/BLAKE2/blob/master/ref/blake2b-ref.c +// The changes in original code were done mostly to accommodate variable round number and to remove +// unnecessary big endian support. + +namespace dev +{ +namespace crypto +{ +namespace +{ +DEV_SIMPLE_EXCEPTION(InvalidInputSize); + +constexpr size_t BLAKE2B_BLOCKBYTES = 128; + +struct blake2b_state +{ + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; +}; + +// clang-format off +constexpr uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +constexpr uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; +// clang-format on + +inline uint64_t load64(const void* src) noexcept +{ + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +} + +inline constexpr uint64_t rotr64(uint64_t w, unsigned c) noexcept +{ + return (w >> c) | (w << (64 - c)); +} + +inline void G(uint8_t r, uint8_t i, uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d, + const uint64_t* m) noexcept +{ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; + d = rotr64(d ^ a, 32); + c = c + d; + b = rotr64(b ^ c, 24); + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; + d = rotr64(d ^ a, 16); + c = c + d; + b = rotr64(b ^ c, 63); +} + +inline void ROUND(uint32_t round, uint64_t* v, const uint64_t* m) noexcept +{ + uint8_t const r = round % 10; + G(r, 0, v[0], v[4], v[8], v[12], m); + G(r, 1, v[1], v[5], v[9], v[13], m); + G(r, 2, v[2], v[6], v[10], v[14], m); + G(r, 3, v[3], v[7], v[11], v[15], m); + G(r, 4, v[0], v[5], v[10], v[15], m); + G(r, 5, v[1], v[6], v[11], v[12], m); + G(r, 6, v[2], v[7], v[8], v[13], m); + G(r, 7, v[3], v[4], v[9], v[14], m); +} + + +void blake2b_compress( + uint32_t rounds, blake2b_state* S, const uint8_t block[BLAKE2B_BLOCKBYTES]) noexcept +{ + uint64_t m[16]; + uint64_t v[16]; + + for (size_t i = 0; i < 16; ++i) + m[i] = load64(block + i * sizeof(m[i])); + + for (size_t i = 0; i < 8; ++i) + v[i] = S->h[i]; + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + for (uint32_t r = 0; r < rounds; ++r) + ROUND(r, v, m); + + for (size_t i = 0; i < 8; ++i) + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; +} + +} // namespace + + +bytes blake2FCompression(uint32_t _rounds, bytesConstRef _stateVector, bytesConstRef _t0, + bytesConstRef _t1, bool _lastBlock, bytesConstRef _messageBlockVector) +{ + if (_stateVector.size() != sizeof(blake2b_state::h)) + BOOST_THROW_EXCEPTION(InvalidInputSize()); + + blake2b_state s{}; + std::memcpy(&s.h, _stateVector.data(), _stateVector.size()); + + if (_t0.size() != sizeof(s.t[0]) || _t1.size() != sizeof(s.t[1])) + BOOST_THROW_EXCEPTION(InvalidInputSize()); + + s.t[0] = load64(_t0.data()); + s.t[1] = load64(_t1.data()); + s.f[0] = _lastBlock ? std::numeric_limits::max() : 0; + + if (_messageBlockVector.size() != BLAKE2B_BLOCKBYTES) + BOOST_THROW_EXCEPTION(InvalidInputSize()); + + uint8_t block[BLAKE2B_BLOCKBYTES]; + std::copy(_messageBlockVector.begin(), _messageBlockVector.end(), &block[0]); + + blake2b_compress(_rounds, &s, block); + + bytes result(sizeof(s.h)); + std::memcpy(&result[0], &s.h[0], result.size()); + + return result; +} + +} // namespace crypto +} // namespace dev \ No newline at end of file diff --git a/src/eth_client/libdevcrypto/Blake2.h b/src/eth_client/libdevcrypto/Blake2.h new file mode 100644 index 0000000000..b3c6a65bbc --- /dev/null +++ b/src/eth_client/libdevcrypto/Blake2.h @@ -0,0 +1,24 @@ +/// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include + +namespace dev +{ +namespace crypto +{ +/// Calculates the compression function F used in the BLAKE2 cryptographic hashing algorithm +/// Throws exception in case input data has incorrect size. +/// @param _rounds the number of rounds +/// @param _stateVector the state vector - 8 unsigned 64-bit little-endian words +/// @param _t0, _t1 offset counters - unsigned 64-bit little-endian words +/// @param _lastBlock the final block indicator flag +/// @param _messageBlock the message block vector - 16 unsigned 64-bit little-endian words +/// @returns updated state vector with unchanged encoding (little-endian) +bytes blake2FCompression(uint32_t _rounds, bytesConstRef _stateVector, bytesConstRef _t0, + bytesConstRef _t1, bool _lastBlock, bytesConstRef _messageBlock); +} +} // namespace dev diff --git a/src/eth_client/libdevcrypto/Common.cpp b/src/eth_client/libdevcrypto/Common.cpp new file mode 100644 index 0000000000..9e7e4b7a7f --- /dev/null +++ b/src/eth_client/libdevcrypto/Common.cpp @@ -0,0 +1,423 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include // conflicts with +#include "Common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CryptoPP.h" +#include "Exceptions.h" +using namespace std; +using namespace dev; +using namespace dev::crypto; + +namespace +{ + +secp256k1_context const* getCtx() +{ + static std::unique_ptr s_ctx{ + secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY), + &secp256k1_context_destroy + }; + return s_ctx.get(); +} + +template +bool toPublicKey(Secret const& _secret, unsigned _flags, array& o_serializedPubkey) +{ + auto* ctx = getCtx(); + secp256k1_pubkey rawPubkey; + // Creation will fail if the secret key is invalid. + if (!secp256k1_ec_pubkey_create(ctx, &rawPubkey, _secret.data())) + return false; + size_t serializedPubkeySize = o_serializedPubkey.size(); + secp256k1_ec_pubkey_serialize( + ctx, o_serializedPubkey.data(), &serializedPubkeySize, &rawPubkey, _flags); + assert(serializedPubkeySize == o_serializedPubkey.size()); + return true; +} +} + +bool dev::SignatureStruct::isValid() const noexcept +{ + static const h256 s_max{"0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"}; + static const h256 s_zero; + + return (v <= 1 && r > s_zero && s > s_zero && r < s_max && s < s_max); +} + +Public dev::toPublic(Secret const& _secret) +{ + std::array serializedPubkey; + if (!toPublicKey(_secret, SECP256K1_EC_UNCOMPRESSED, serializedPubkey)) + return {}; + + // Expect single byte header of value 0x04 -- uncompressed public key. + assert(serializedPubkey[0] == 0x04); + + // Create the Public skipping the header. + return Public{&serializedPubkey[1], Public::ConstructFromPointer}; +} + +Public dev::toPublic(PublicCompressed const& _publicCompressed) +{ + auto* ctx = getCtx(); + + secp256k1_pubkey rawPubkey; + if (!secp256k1_ec_pubkey_parse( + ctx, &rawPubkey, _publicCompressed.data(), PublicCompressed::size)) + return {}; + + std::array serializedPubkey; + auto serializedPubkeySize = serializedPubkey.size(); + secp256k1_ec_pubkey_serialize( + ctx, serializedPubkey.data(), &serializedPubkeySize, &rawPubkey, SECP256K1_EC_UNCOMPRESSED); + assert(serializedPubkeySize == serializedPubkey.size()); + // Expect single byte header of value 0x04 -- uncompressed public key. + assert(serializedPubkey[0] == 0x04); + // Create the Public skipping the header. + return Public{&serializedPubkey[1], Public::ConstructFromPointer}; +} + +PublicCompressed dev::toPublicCompressed(Secret const& _secret) +{ + PublicCompressed serializedPubkey; + if (!toPublicKey(_secret, SECP256K1_EC_COMPRESSED, serializedPubkey.asArray())) + return {}; + + // Expect single byte header of value 0x02 or 0x03 -- compressed public key. + assert(serializedPubkey[0] == 0x02 || serializedPubkey[0] == 0x03); + + return serializedPubkey; +} + +Address dev::toAddress(Public const& _public) +{ + return right160(sha3(_public.ref())); +} + +Address dev::toAddress(Secret const& _secret) +{ + return toAddress(toPublic(_secret)); +} + +Address dev::toAddress(Address const& _from, u256 const& _nonce) +{ + return right160(sha3(rlpList(_from, _nonce))); +} + +void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher) +{ + bytes io = _plain.toBytes(); + Secp256k1PP::get()->encrypt(_k, io); + o_cipher = std::move(io); +} + +bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext) +{ + bytes io = _cipher.toBytes(); + Secp256k1PP::get()->decrypt(_k, io); + if (io.empty()) + return false; + o_plaintext = std::move(io); + return true; +} + +void dev::encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher) +{ + encryptECIES(_k, bytesConstRef(), _plain, o_cipher); +} + +void dev::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytesConstRef _plain, bytes& o_cipher) +{ + bytes io = _plain.toBytes(); + Secp256k1PP::get()->encryptECIES(_k, _sharedMacData, io); + o_cipher = std::move(io); +} + +bool dev::decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext) +{ + return decryptECIES(_k, bytesConstRef(), _cipher, o_plaintext); +} + +bool dev::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytesConstRef _cipher, bytes& o_plaintext) +{ + bytes io = _cipher.toBytes(); + if (!Secp256k1PP::get()->decryptECIES(_k, _sharedMacData, io)) + return false; + o_plaintext = std::move(io); + return true; +} + +void dev::encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher) +{ + // TODO: @alex @subtly do this properly. + encrypt(KeyPair(_k).pub(), _plain, o_cipher); +} + +bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) +{ + // TODO: @alex @subtly do this properly. + return decrypt(_k, _cipher, o_plain); +} + +std::pair dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain) +{ + h128 iv(Nonce::get().makeInsecure()); + return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); +} + +bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain) +{ + if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) + return bytes(); + CryptoPP::SecByteBlock key(_k.data(), _k.size()); + try + { + CryptoPP::CTR_Mode::Encryption e; + e.SetKeyWithIV(key, key.size(), _iv.data()); + bytes ret(_plain.size()); + e.ProcessData(ret.data(), _plain.data(), _plain.size()); + return ret; + } + catch (CryptoPP::Exception& _e) + { + cerr << _e.what() << endl; + return bytes(); + } +} + +bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) +{ + if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) + return bytesSec(); + CryptoPP::SecByteBlock key(_k.data(), _k.size()); + try + { + CryptoPP::CTR_Mode::Decryption d; + d.SetKeyWithIV(key, key.size(), _iv.data()); + bytesSec ret(_cipher.size()); + d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size()); + return ret; + } + catch (CryptoPP::Exception& _e) + { + cerr << _e.what() << endl; + return bytesSec(); + } +} + +Public dev::recover(Signature const& _sig, h256 const& _message) +{ + int v = _sig[64]; + if (v > 3) + return {}; + + auto* ctx = getCtx(); + secp256k1_ecdsa_recoverable_signature rawSig; + if (!secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rawSig, _sig.data(), v)) + return {}; + + secp256k1_pubkey rawPubkey; + if (!secp256k1_ecdsa_recover(ctx, &rawPubkey, &rawSig, _message.data())) + return {}; + + std::array serializedPubkey; + size_t serializedPubkeySize = serializedPubkey.size(); + secp256k1_ec_pubkey_serialize( + ctx, serializedPubkey.data(), &serializedPubkeySize, + &rawPubkey, SECP256K1_EC_UNCOMPRESSED + ); + assert(serializedPubkeySize == serializedPubkey.size()); + // Expect single byte header of value 0x04 -- uncompressed public key. + assert(serializedPubkey[0] == 0x04); + // Create the Public skipping the header. + return Public{&serializedPubkey[1], Public::ConstructFromPointer}; +} + +static const u256 c_secp256k1n("115792089237316195423570985008687907852837564279074904382605163141518161494337"); + +Signature dev::sign(Secret const& _k, h256 const& _hash) +{ + auto* ctx = getCtx(); + secp256k1_ecdsa_recoverable_signature rawSig; + if (!secp256k1_ecdsa_sign_recoverable(ctx, &rawSig, _hash.data(), _k.data(), nullptr, nullptr)) + return {}; + + Signature s; + int v = 0; + secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, s.data(), &v, &rawSig); + + SignatureStruct& ss = *reinterpret_cast(&s); + ss.v = static_cast(v); + if (ss.s > c_secp256k1n / 2) + { + ss.v = static_cast(ss.v ^ 1); + ss.s = h256(c_secp256k1n - u256(ss.s)); + } + assert(ss.s <= c_secp256k1n / 2); + return s; +} + +bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash) +{ + // TODO: Verify w/o recovery (if faster). + if (!_p) + return false; + return _p == recover(_s, _hash); +} + +bool dev::verify(PublicCompressed const& _key, h512 const& _signature, h256 const& _hash) +{ + auto* ctx = getCtx(); + + secp256k1_ecdsa_signature rawSig; + if (!secp256k1_ecdsa_signature_parse_compact(ctx, &rawSig, _signature.data())) + return false; + + secp256k1_pubkey rawPubkey; + if (!secp256k1_ec_pubkey_parse(ctx, &rawPubkey, _key.data(), PublicCompressed::size)) + return false; // Invalid public key. + + return secp256k1_ecdsa_verify(ctx, &rawSig, _hash.data(), &rawPubkey); +} + +bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) +{ + bytesSec ret(_dkLen); + if (CryptoPP::PKCS5_PBKDF2_HMAC().DeriveKey( + ret.writable().data(), + _dkLen, + 0, + reinterpret_cast(_pass.data()), + _pass.size(), + _salt.data(), + _salt.size(), + _iterations + ) != _iterations) + BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); + return ret; +} + +bytesSec dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) +{ + bytesSec ret(_dkLen); + if (libscrypt_scrypt( + reinterpret_cast(_pass.data()), + _pass.size(), + _salt.data(), + _salt.size(), + _n, + _r, + _p, + ret.writable().data(), + _dkLen + ) != 0) + BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); + return ret; +} + +KeyPair::KeyPair(Secret const& _sec): + m_secret(_sec), + m_public(toPublic(_sec)) +{ + // Assign address only if the secret key is valid. + if (m_public) + m_address = toAddress(m_public); +} + +KeyPair KeyPair::create() +{ + while (true) + { + KeyPair keyPair(Secret::random()); + if (keyPair.address()) + return keyPair; + } +} + +h256 crypto::kdf(Secret const& _priv, h256 const& _hash) +{ + // H(H(r||k)^h) + h256 s; + sha3mac(Secret::random().ref(), _priv.ref(), s.ref()); + s ^= _hash; + sha3(s.ref(), s.ref()); + + if (!s || !_hash || !_priv) + BOOST_THROW_EXCEPTION(InvalidState()); + return s; +} + +Secret Nonce::next() +{ + Guard l(x_value); + if (!m_value) + { + m_value = Secret::random(); + if (!m_value) + BOOST_THROW_EXCEPTION(InvalidState()); + } + m_value = sha3Secure(m_value.ref()); + return sha3(~m_value); +} + +bool ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s) noexcept +{ + auto* ctx = getCtx(); + static_assert(sizeof(Secret) == 32, "Invalid Secret type size"); + secp256k1_pubkey rawPubkey; + std::array serializedPubKey{{0x04}}; + std::copy(_r.asArray().begin(), _r.asArray().end(), serializedPubKey.begin() + 1); + if (!secp256k1_ec_pubkey_parse(ctx, &rawPubkey, serializedPubKey.data(), serializedPubKey.size())) + return false; // Invalid public key. + // FIXME: We should verify the public key when constructed, maybe even keep + // secp256k1_pubkey as the internal data of Public. + std::array compressedPoint; + if (!secp256k1_ecdh(ctx, compressedPoint.data(), &rawPubkey, _s.data(), nullptr, nullptr)) + return false; // Invalid secret key. + std::copy(compressedPoint.begin() + 1, compressedPoint.end(), o_s.writable().data()); + return true; +} + +bytes ecies::kdf(Secret const& _z, bytes const& _s1, unsigned kdByteLen) +{ + auto reps = ((kdByteLen + 7) * 8) / 512; + // SEC/ISO/Shoup specify counter size SHOULD be equivalent + // to size of hash output, however, it also notes that + // the 4 bytes is okay. NIST specifies 4 bytes. + std::array ctr{{0, 0, 0, 1}}; + bytes k; + secp256k1_sha256_t ctx; + for (unsigned i = 0; i <= reps; i++) + { + secp256k1_sha256_initialize(&ctx); + secp256k1_sha256_write(&ctx, ctr.data(), ctr.size()); + secp256k1_sha256_write(&ctx, _z.data(), Secret::size); + secp256k1_sha256_write(&ctx, _s1.data(), _s1.size()); + // append hash to k + std::array digest; + secp256k1_sha256_finalize(&ctx, digest.data()); + + k.reserve(k.size() + h256::size); + move(digest.begin(), digest.end(), back_inserter(k)); + + if (++ctr[3] || ++ctr[2] || ++ctr[1] || ++ctr[0]) + continue; + } + + k.resize(kdByteLen); + return k; +} diff --git a/src/eth_client/libdevcrypto/Common.h b/src/eth_client/libdevcrypto/Common.h new file mode 100644 index 0000000000..fa6c87b256 --- /dev/null +++ b/src/eth_client/libdevcrypto/Common.h @@ -0,0 +1,209 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +/** + * Ethereum-specific data structures & algorithms. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace dev +{ + +using Secret = SecureFixedHash<32>; + +/// A public key: 64 bytes. +/// @NOTE This is not endian-specific; it's just a bunch of bytes. +using Public = h512; + +/// A public key in compressed format: 33 bytes. +/// @NOTE This is not endian-specific; it's just a bunch of bytes. +using PublicCompressed = FixedHash<33>; + +/// A signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64. +/// @NOTE This is not endian-specific; it's just a bunch of bytes. +using Signature = h520; + +struct SignatureStruct +{ + SignatureStruct() = default; + SignatureStruct(Signature const& _s) { *(h520*)this = _s; } + SignatureStruct(h256 const& _r, h256 const& _s, byte _v): r(_r), s(_s), v(_v) {} + operator Signature() const { return *(h520 const*)this; } + + /// @returns true if r,s,v values are valid, otherwise false + bool isValid() const noexcept; + + h256 r; + h256 s; + byte v = 0; +}; + +/// A vector of secrets. +using Secrets = std::vector; + +/// Convert a secret key into the public key equivalent. +Public toPublic(Secret const& _secret); + +/// Convert a compressed public key into the uncompressed equivalent. +Public toPublic(PublicCompressed const& _publicCompressed); + +/// Convert a secret key into the public key in compressed format. +PublicCompressed toPublicCompressed(Secret const& _secret); + +/// Convert a public key to address. +Address toAddress(Public const& _public); + +/// Convert a secret key into address of public key equivalent. +/// @returns 0 if it's not a valid secret key. +Address toAddress(Secret const& _secret); + +// Convert transaction from and nonce to address. +Address toAddress(Address const& _from, u256 const& _nonce); + +/// Encrypts plain text using Public key. +void encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher); + +/// Decrypts cipher using Secret key. +bool decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); + +/// Symmetric encryption. +void encryptSym(Secret const& _k, bytesConstRef _plain, bytes& o_cipher); + +/// Symmetric decryption. +bool decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); + +/// Encrypt payload using ECIES standard with AES128-CTR. +void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); + +/// Encrypt payload using ECIES standard with AES128-CTR. +/// @a _sharedMacData is shared authenticated data. +void encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytesConstRef _plain, bytes& o_cipher); + +/// Decrypt payload using ECIES standard with AES128-CTR. +bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); + +/// Decrypt payload using ECIES standard with AES128-CTR. +/// @a _sharedMacData is shared authenticated data. +bool decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytesConstRef _cipher, bytes& o_plaintext); + +/// Encrypts payload with random IV/ctr using AES128-CTR. +std::pair encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain); + +/// Encrypts payload with specified IV/ctr using AES128-CTR. +bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain); + +/// Decrypts payload with specified IV/ctr using AES128-CTR. +bytesSec decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); + +/// Encrypts payload with specified IV/ctr using AES128-CTR. +inline bytes encryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } +inline bytes encryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } + +/// Decrypts payload with specified IV/ctr using AES128-CTR. +inline bytesSec decryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } +inline bytesSec decryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } + +/// Recovers Public key from signed message hash. +Public recover(Signature const& _sig, h256 const& _hash); + +/// Returns siganture of message hash. +Signature sign(Secret const& _k, h256 const& _hash); + +/// Verify signature. +bool verify(Public const& _k, Signature const& _s, h256 const& _hash); + +// Verify signature with compressed public key +bool verify(PublicCompressed const& _key, h512 const& _signature, h256 const& _hash); + +/// Derive key via PBKDF2. +bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); + +/// Derive key via Scrypt. +bytesSec scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); + +/// 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: + /// Normal constructor - populates object from the given secret key. + /// If the secret key is invalid the constructor succeeds, but public key + /// and address stay "null". + KeyPair(Secret const& _sec); + + /// Create a new, randomly generated object. + static KeyPair create(); + + Secret const& secret() 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; } + + bool operator==(KeyPair const& _c) const { return m_public == _c.m_public; } + bool operator!=(KeyPair const& _c) const { return m_public != _c.m_public; } + +private: + Secret m_secret; + Public m_public; + Address m_address; +}; + +namespace crypto +{ + +DEV_SIMPLE_EXCEPTION(InvalidState); + +/// Key derivation +h256 kdf(Secret const& _priv, h256 const& _hash); + +/** + * @brief Generator for non-repeating nonce material. + * The Nonce class should only be used when a non-repeating nonce + * is required and, in its current form, not recommended for signatures. + * This is primarily because the key-material for signatures is + * encrypted on disk whereas the seed for Nonce is not. + * Thus, Nonce's primary intended use at this time is for networking + * where the key is also stored in plaintext. + */ +class Nonce +{ +public: + /// Returns the next nonce (might be read from a file). + static Secret get() { static Nonce s; return s.next(); } + +private: + Nonce() = default; + + /// @returns the next nonce. + Secret next(); + + std::mutex x_value; + Secret m_value; +}; + +namespace ecdh +{ + +bool agree(Secret const& _s, Public const& _r, Secret& o_s) noexcept; + +} + +namespace ecies +{ + +bytes kdf(Secret const& _z, bytes const& _s1, unsigned kdByteLen); + +} +} +} diff --git a/src/eth_client/libdevcrypto/CryptoPP.cpp b/src/eth_client/libdevcrypto/CryptoPP.cpp new file mode 100644 index 0000000000..b128822990 --- /dev/null +++ b/src/eth_client/libdevcrypto/CryptoPP.cpp @@ -0,0 +1,233 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include // conflicts with +#include "CryptoPP.h" +#include +#include +#include +#include +#include + + +using namespace dev; +using namespace dev::crypto; + +static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); +static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); +static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); + +namespace +{ +class Secp256k1PPCtx +{ +public: + CryptoPP::OID m_oid; + + std::mutex x_rng; + CryptoPP::AutoSeededRandomPool m_rng; + + std::mutex x_params; + CryptoPP::DL_GroupParameters_EC m_params; + + CryptoPP::DL_GroupParameters_EC::EllipticCurve m_curve; + + CryptoPP::Integer m_q; + CryptoPP::Integer m_qs; + + static Secp256k1PPCtx& get() + { + static Secp256k1PPCtx ctx; + return ctx; + } + +private: + Secp256k1PPCtx(): + m_oid(CryptoPP::ASN1::secp256k1()), m_params(m_oid), m_curve(m_params.GetCurve()), + m_q(m_params.GetGroupOrder()), m_qs(m_params.GetSubgroupOrder()) + {} +}; + +inline CryptoPP::ECP::Point publicToPoint(Public const& _p) { CryptoPP::Integer x(_p.data(), 32); CryptoPP::Integer y(_p.data() + 32, 32); return CryptoPP::ECP::Point(x,y); } + +inline CryptoPP::Integer secretToExponent(Secret const& _s) { return CryptoPP::Integer(_s.data(), Secret::size); } + +} + +Secp256k1PP* Secp256k1PP::get() +{ + static Secp256k1PP s_this; + return &s_this; +} + +void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher) +{ + encryptECIES(_k, bytesConstRef(), io_cipher); +} + +void Secp256k1PP::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher) +{ + // interop w/go ecies implementation + auto r = KeyPair::create(); + Secret z; + ecdh::agree(r.secret(), _k, z); + auto key = ecies::kdf(z, bytes(), 32); + bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); + bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); + CryptoPP::SHA256 ctx; + ctx.Update(mKeyMaterial.data(), mKeyMaterial.size()); + bytes mKey(32); + ctx.Final(mKey.data()); + + auto iv = h128::random(); + bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), iv, bytesConstRef(&io_cipher)); + if (cipherText.empty()) + return; + + bytes msg(1 + Public::size + h128::size + cipherText.size() + 32); + msg[0] = 0x04; + r.pub().ref().copyTo(bytesRef(&msg).cropped(1, Public::size)); + iv.ref().copyTo(bytesRef(&msg).cropped(1 + Public::size, h128::size)); + bytesRef msgCipherRef = bytesRef(&msg).cropped(1 + Public::size + h128::size, cipherText.size()); + bytesConstRef(&cipherText).copyTo(msgCipherRef); + + // tag message + CryptoPP::HMAC hmacctx(mKey.data(), mKey.size()); + bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size()); + hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); + hmacctx.Update(_sharedMacData.data(), _sharedMacData.size()); + hmacctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size()); + + io_cipher.resize(msg.size()); + io_cipher.swap(msg); +} + +bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text) +{ + return decryptECIES(_k, bytesConstRef(), io_text); +} + +bool Secp256k1PP::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text) +{ + + // interop w/go ecies implementation + + // io_cipher[0] must be 2, 3, or 4, else invalidpublickey + if (io_text.empty() || io_text[0] < 2 || io_text[0] > 4) + // invalid message: publickey + return false; + + if (io_text.size() < (1 + Public::size + h128::size + 1 + h256::size)) + // invalid message: length + return false; + + Secret z; + if (!ecdh::agree(_k, *(Public*)(io_text.data() + 1), z)) + return false; // Invalid pubkey or seckey. + auto key = ecies::kdf(z, bytes(), 64); + bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); + bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); + bytes mKey(32); + CryptoPP::SHA256 ctx; + ctx.Update(mKeyMaterial.data(), mKeyMaterial.size()); + ctx.Final(mKey.data()); + + bytes plain; + size_t cipherLen = io_text.size() - 1 - Public::size - h128::size - h256::size; + bytesConstRef cipherWithIV(io_text.data() + 1 + Public::size, h128::size + cipherLen); + bytesConstRef cipherIV = cipherWithIV.cropped(0, h128::size); + bytesConstRef cipherNoIV = cipherWithIV.cropped(h128::size, cipherLen); + bytesConstRef msgMac(cipherNoIV.data() + cipherLen, h256::size); + h128 iv(cipherIV.toBytes()); + + // verify tag + CryptoPP::HMAC hmacctx(mKey.data(), mKey.size()); + hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); + hmacctx.Update(_sharedMacData.data(), _sharedMacData.size()); + h256 mac; + hmacctx.Final(mac.data()); + for (unsigned i = 0; i < h256::size; i++) + if (mac[i] != msgMac[i]) + return false; + + plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure(); + io_text.resize(plain.size()); + io_text.swap(plain); + + return true; +} + +void Secp256k1PP::encrypt(Public const& _k, bytes& io_cipher) +{ + auto& ctx = Secp256k1PPCtx::get(); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CryptoPP::ECIES::Encryptor e; +#pragma GCC diagnostic pop +#pragma clang diagnostic pop + + { + Guard l(ctx.x_params); + e.AccessKey().Initialize(ctx.m_params, publicToPoint(_k)); + } + + + size_t plen = io_cipher.size(); + bytes ciphertext; + ciphertext.resize(e.CiphertextLength(plen)); + + { + Guard l(ctx.x_rng); + e.Encrypt(ctx.m_rng, io_cipher.data(), plen, ciphertext.data()); + } + + memset(io_cipher.data(), 0, io_cipher.size()); + io_cipher = std::move(ciphertext); +} + +void Secp256k1PP::decrypt(Secret const& _k, bytes& io_text) +{ + auto& ctx = Secp256k1PPCtx::get(); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CryptoPP::ECIES::Decryptor d; +#pragma GCC diagnostic pop +#pragma clang diagnostic pop + + { + Guard l(ctx.x_params); + d.AccessKey().Initialize(ctx.m_params, secretToExponent(_k)); + } + + if (!io_text.size()) + { + io_text.resize(1); + io_text[0] = 0; + } + + size_t clen = io_text.size(); + bytes plain; + plain.resize(d.MaxPlaintextLength(io_text.size())); + + CryptoPP::DecodingResult r; + { + Guard l(ctx.x_rng); + r = d.Decrypt(ctx.m_rng, io_text.data(), clen, plain.data()); + } + + if (!r.isValidCoding) + { + io_text.clear(); + return; + } + + io_text.resize(r.messageLength); + io_text = std::move(plain); +} diff --git a/src/eth_client/libdevcrypto/CryptoPP.h b/src/eth_client/libdevcrypto/CryptoPP.h new file mode 100644 index 0000000000..88a3884880 --- /dev/null +++ b/src/eth_client/libdevcrypto/CryptoPP.h @@ -0,0 +1,52 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +/** + * CryptoPP headers and primitive helper methods + */ + +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace crypto +{ +/// Amount of bytes added when encrypting with encryptECIES. +static const unsigned c_eciesOverhead = 113; + +/** + * CryptoPP secp256k1 algorithms. + * @todo Collect ECIES methods into class. + */ +class Secp256k1PP +{ +public: + static Secp256k1PP* get(); + + /// Encrypts text (replace input). (ECIES w/XOR-SHA1) + void encrypt(Public const& _k, bytes& io_cipher); + + /// Decrypts text (replace input). (ECIES w/XOR-SHA1) + void decrypt(Secret const& _k, bytes& io_text); + + /// Encrypts text (replace input). (ECIES w/AES128-CTR-SHA256) + void encryptECIES(Public const& _k, bytes& io_cipher); + + /// Encrypts text (replace input). (ECIES w/AES128-CTR-SHA256) + void encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher); + + /// Decrypts text (replace input). (ECIES w/AES128-CTR-SHA256) + bool decryptECIES(Secret const& _k, bytes& io_text); + + /// Decrypts text (replace input). (ECIES w/AES128-CTR-SHA256) + bool decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text); + +private: + Secp256k1PP() = default; +}; + +} +} + diff --git a/src/eth_client/libdevcrypto/Exceptions.h b/src/eth_client/libdevcrypto/Exceptions.h new file mode 100644 index 0000000000..4c59cd2ae9 --- /dev/null +++ b/src/eth_client/libdevcrypto/Exceptions.h @@ -0,0 +1,19 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include + +namespace dev +{ +namespace crypto +{ + +/// Rare malfunction of cryptographic functions. +DEV_SIMPLE_EXCEPTION(CryptoException); + +} +} diff --git a/src/eth_client/libdevcrypto/Hash.cpp b/src/eth_client/libdevcrypto/Hash.cpp new file mode 100644 index 0000000000..1a43315fec --- /dev/null +++ b/src/eth_client/libdevcrypto/Hash.cpp @@ -0,0 +1,424 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include "Hash.h" +#include + +using namespace dev; + +namespace dev +{ + +h256 sha256(bytesConstRef _input) noexcept +{ + secp256k1_sha256_t ctx; + secp256k1_sha256_initialize(&ctx); + secp256k1_sha256_write(&ctx, _input.data(), _input.size()); + h256 hash; + secp256k1_sha256_finalize(&ctx, hash.data()); + return hash; +} + +namespace rmd160 +{ + +/********************************************************************\ + * + * FILE: rmd160.h + * FILE: rmd160.c + * + * CONTENTS: Header file for a sample C-implementation of the + * RIPEMD-160 hash-function. + * TARGET: any computer with an ANSI C compiler + * + * AUTHOR: Antoon Bosselaers, ESAT-COSIC + * DATE: 1 March 1996 + * VERSION: 1.0 + * + * Copyright (c) Katholieke Universiteit Leuven + * 1996, All Rights Reserved + * + \********************************************************************/ + +// Adapted into "header-only" format by Gav Wood. + +/* macro definitions */ + +#define RMDsize 160 + +/* collect four bytes into one word: */ +#define BYTES_TO_DWORD(strptr) \ +(((uint32_t) *((strptr)+3) << 24) | \ +((uint32_t) *((strptr)+2) << 16) | \ +((uint32_t) *((strptr)+1) << 8) | \ +((uint32_t) *(strptr))) + +/* ROL(x, n) cyclically rotates x over n bits to the left */ +/* x must be of an unsigned 32 bits type and 0 <= n < 32. */ +#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* the five basic functions F(), G() and H() */ +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z) ((x) ^ ((y) | ~(z))) + +/* the ten basic operations FF() through III() */ +#define FF(a, b, c, d, e, x, s) {\ +(a) += F((b), (c), (d)) + (x);\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define GG(a, b, c, d, e, x, s) {\ +(a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define HH(a, b, c, d, e, x, s) {\ +(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define II(a, b, c, d, e, x, s) {\ +(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define JJ(a, b, c, d, e, x, s) {\ +(a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define FFF(a, b, c, d, e, x, s) {\ +(a) += F((b), (c), (d)) + (x);\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define GGG(a, b, c, d, e, x, s) {\ +(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define HHH(a, b, c, d, e, x, s) {\ +(a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define III(a, b, c, d, e, x, s) {\ +(a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} +#define JJJ(a, b, c, d, e, x, s) {\ +(a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ +(a) = ROL((a), (s)) + (e);\ +(c) = ROL((c), 10);\ +} + +void MDinit(uint32_t *MDbuf) +{ + MDbuf[0] = 0x67452301UL; + MDbuf[1] = 0xefcdab89UL; + MDbuf[2] = 0x98badcfeUL; + MDbuf[3] = 0x10325476UL; + MDbuf[4] = 0xc3d2e1f0UL; + + return; +} + +/********************************************************************/ + +void MDcompress(uint32_t *MDbuf, uint32_t *X) +{ + uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], + dd = MDbuf[3], ee = MDbuf[4]; + uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], + ddd = MDbuf[3], eee = MDbuf[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[ 0], 11); + FF(ee, aa, bb, cc, dd, X[ 1], 14); + FF(dd, ee, aa, bb, cc, X[ 2], 15); + FF(cc, dd, ee, aa, bb, X[ 3], 12); + FF(bb, cc, dd, ee, aa, X[ 4], 5); + FF(aa, bb, cc, dd, ee, X[ 5], 8); + FF(ee, aa, bb, cc, dd, X[ 6], 7); + FF(dd, ee, aa, bb, cc, X[ 7], 9); + FF(cc, dd, ee, aa, bb, X[ 8], 11); + FF(bb, cc, dd, ee, aa, X[ 9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[ 7], 7); + GG(dd, ee, aa, bb, cc, X[ 4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[ 1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[ 6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[ 3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[ 0], 12); + GG(ee, aa, bb, cc, dd, X[ 9], 15); + GG(dd, ee, aa, bb, cc, X[ 5], 9); + GG(cc, dd, ee, aa, bb, X[ 2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[ 3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[ 4], 7); + HH(ee, aa, bb, cc, dd, X[ 9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[ 8], 13); + HH(bb, cc, dd, ee, aa, X[ 1], 15); + HH(aa, bb, cc, dd, ee, X[ 2], 14); + HH(ee, aa, bb, cc, dd, X[ 7], 8); + HH(dd, ee, aa, bb, cc, X[ 0], 13); + HH(cc, dd, ee, aa, bb, X[ 6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[ 5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[ 1], 11); + II(bb, cc, dd, ee, aa, X[ 9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[ 0], 14); + II(cc, dd, ee, aa, bb, X[ 8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[ 4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[ 3], 14); + II(cc, dd, ee, aa, bb, X[ 7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[ 5], 6); + II(dd, ee, aa, bb, cc, X[ 6], 5); + II(cc, dd, ee, aa, bb, X[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[ 4], 9); + JJ(aa, bb, cc, dd, ee, X[ 0], 15); + JJ(ee, aa, bb, cc, dd, X[ 5], 5); + JJ(dd, ee, aa, bb, cc, X[ 9], 11); + JJ(cc, dd, ee, aa, bb, X[ 7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[ 2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[ 1], 12); + JJ(bb, cc, dd, ee, aa, X[ 3], 13); + JJ(aa, bb, cc, dd, ee, X[ 8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[ 6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); + + /* combine results */ + ddd += cc + MDbuf[1]; /* final result for MDbuf[0] */ + MDbuf[1] = MDbuf[2] + dd + eee; + MDbuf[2] = MDbuf[3] + ee + aaa; + MDbuf[3] = MDbuf[4] + aa + bbb; + MDbuf[4] = MDbuf[0] + bb + ccc; + MDbuf[0] = ddd; + + return; +} + +void MDfinish(uint32_t *MDbuf, byte const *strptr, uint32_t lswlen, uint32_t mswlen) +{ + unsigned int i; /* counter */ + uint32_t X[16]; /* message words */ + + memset(X, 0, 16*sizeof(uint32_t)); + + /* put bytes from strptr into X */ + for (i=0; i<(lswlen&63); i++) { + /* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */ + X[i>>2] ^= (uint32_t) *strptr++ << (8 * (i&3)); + } + + /* append the bit m_n == 1 */ + X[(lswlen>>2)&15] ^= (uint32_t)1 << (8*(lswlen&3) + 7); + + if ((lswlen & 63) > 55) { + /* length goes to next block */ + MDcompress(MDbuf, X); + memset(X, 0, 16*sizeof(uint32_t)); + } + + /* append length in bits*/ + X[14] = lswlen << 3; + X[15] = (lswlen >> 29) | (mswlen << 3); + MDcompress(MDbuf, X); + + return; +} + +#undef ROL +#undef F +#undef G +#undef H +#undef I +#undef J +#undef FF +#undef GG +#undef HH +#undef II +#undef JJ +#undef FFF +#undef GGG +#undef HHH +#undef III +#undef JJJ + +} + +/* + * @returns RMD(_input) + */ +h160 ripemd160(bytesConstRef _input) +{ + h160 hashcode; + uint32_t buffer[RMDsize / 32]; // contains (A, B, C, D(, E)) + uint32_t current[16]; // current 16-word chunk + + // initialize + rmd160::MDinit(buffer); + byte const* message = _input.data(); + uint32_t remaining = _input.size(); // # of bytes not yet processed + + // process message in 16x 4-byte chunks + for (; remaining >= 64; remaining -= 64) + { + for (unsigned i = 0; i < 16; i++) + { + current[i] = BYTES_TO_DWORD(message); + message += 4; + } + rmd160::MDcompress(buffer, current); + } + // length mod 64 bytes left + + // finish: + rmd160::MDfinish(buffer, message, _input.size(), 0); + + for (unsigned i = 0; i < RMDsize / 8; i += 4) + { + hashcode[i] = buffer[i >> 2]; // implicit cast to byte + hashcode[i + 1] = (buffer[i >> 2] >> 8); //extracts the 8 least + hashcode[i + 2] = (buffer[i >> 2] >> 16); // significant bits. + hashcode[i + 3] = (buffer[i >> 2] >> 24); + } + + return hashcode; +} + +#undef BYTES_TO_DWORD +#undef RMDsize + +} diff --git a/src/eth_client/libdevcrypto/Hash.h b/src/eth_client/libdevcrypto/Hash.h new file mode 100644 index 0000000000..58d2d35b6e --- /dev/null +++ b/src/eth_client/libdevcrypto/Hash.h @@ -0,0 +1,20 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +/** + * The FixedHash fixed-size "hash" container type. + */ + +#pragma once + +#include "libdevcore/FixedHash.h" +#include "libdevcore/vector_ref.h" + +namespace dev +{ + +h256 sha256(bytesConstRef _input) noexcept; + +h160 ripemd160(bytesConstRef _input); + +} diff --git a/src/eth_client/libdevcrypto/LibSnark.cpp b/src/eth_client/libdevcrypto/LibSnark.cpp new file mode 100644 index 0000000000..e68803763c --- /dev/null +++ b/src/eth_client/libdevcrypto/LibSnark.cpp @@ -0,0 +1,187 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2017-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::crypto; + +namespace +{ + +DEV_SIMPLE_EXCEPTION(InvalidEncoding); + +void initLibSnark() noexcept +{ + static bool s_initialized = []() noexcept + { + libff::inhibit_profiling_info = true; + libff::inhibit_profiling_counters = true; + libff::alt_bn128_pp::init_public_params(); + return true; + }(); + (void)s_initialized; +} + +libff::bigint toLibsnarkBigint(h256 const& _x) +{ + libff::bigint b; + auto const N = b.N; + constexpr size_t L = sizeof(b.data[0]); + static_assert(sizeof(mp_limb_t) == L, "Unexpected limb size in libff::bigint."); + for (size_t i = 0; i < N; i++) + for (size_t j = 0; j < L; j++) + b.data[N - 1 - i] |= mp_limb_t(_x[i * L + j]) << (8 * (L - 1 - j)); + return b; +} + +h256 fromLibsnarkBigint(libff::bigint const& _b) +{ + static size_t const N = static_cast(_b.N); + static size_t const L = sizeof(_b.data[0]); + static_assert(sizeof(mp_limb_t) == L, "Unexpected limb size in libff::bigint."); + h256 x; + for (size_t i = 0; i < N; i++) + for (size_t j = 0; j < L; j++) + x[i * L + j] = uint8_t(_b.data[N - 1 - i] >> (8 * (L - 1 - j))); + return x; +} + +libff::alt_bn128_Fq decodeFqElement(dev::bytesConstRef _data) +{ + // h256::AlignLeft ensures that the h256 is zero-filled on the right if _data + // is too short. + h256 xbin(_data, h256::AlignLeft); + // TODO: Consider using a compiler time constant for comparison. + if (u256(xbin) >= u256(fromLibsnarkBigint(libff::alt_bn128_Fq::mod))) + BOOST_THROW_EXCEPTION(InvalidEncoding()); + return toLibsnarkBigint(xbin); +} + +libff::alt_bn128_G1 decodePointG1(dev::bytesConstRef _data) +{ + libff::alt_bn128_Fq x = decodeFqElement(_data.cropped(0)); + libff::alt_bn128_Fq y = decodeFqElement(_data.cropped(32)); + if (x == libff::alt_bn128_Fq::zero() && y == libff::alt_bn128_Fq::zero()) + return libff::alt_bn128_G1::zero(); + libff::alt_bn128_G1 p(x, y, libff::alt_bn128_Fq::one()); + if (!p.is_well_formed()) + BOOST_THROW_EXCEPTION(InvalidEncoding()); + return p; +} + +bytes encodePointG1(libff::alt_bn128_G1 _p) +{ + if (_p.is_zero()) + return bytes(64, 0); + _p.to_affine_coordinates(); + return + fromLibsnarkBigint(_p.X.as_bigint()).asBytes() + + fromLibsnarkBigint(_p.Y.as_bigint()).asBytes(); +} + +libff::alt_bn128_Fq2 decodeFq2Element(dev::bytesConstRef _data) +{ + // Encoding: c1 (256 bits) c0 (256 bits) + // "Big endian", just like the numbers + return libff::alt_bn128_Fq2( + decodeFqElement(_data.cropped(32)), + decodeFqElement(_data.cropped(0)) + ); +} + +libff::alt_bn128_G2 decodePointG2(dev::bytesConstRef _data) +{ + libff::alt_bn128_Fq2 const x = decodeFq2Element(_data); + libff::alt_bn128_Fq2 const y = decodeFq2Element(_data.cropped(64)); + if (x == libff::alt_bn128_Fq2::zero() && y == libff::alt_bn128_Fq2::zero()) + return libff::alt_bn128_G2::zero(); + libff::alt_bn128_G2 p(x, y, libff::alt_bn128_Fq2::one()); + if (!p.is_well_formed()) + BOOST_THROW_EXCEPTION(InvalidEncoding()); + return p; +} + +} + +pair dev::crypto::alt_bn128_pairing_product(dev::bytesConstRef _in) +{ + // Input: list of pairs of G1 and G2 points + // Output: 1 if pairing evaluates to 1, 0 otherwise (left-padded to 32 bytes) + + size_t constexpr pairSize = 2 * 32 + 2 * 64; + size_t const pairs = _in.size() / pairSize; + if (pairs * pairSize != _in.size()) + // Invalid length. + return {false, bytes{}}; + + try + { + initLibSnark(); + libff::alt_bn128_Fq12 x = libff::alt_bn128_Fq12::one(); + for (size_t i = 0; i < pairs; ++i) + { + bytesConstRef const pair = _in.cropped(i * pairSize, pairSize); + libff::alt_bn128_G1 const g1 = decodePointG1(pair); + libff::alt_bn128_G2 const p = decodePointG2(pair.cropped(2 * 32)); + if (-libff::alt_bn128_G2::scalar_field::one() * p + p != libff::alt_bn128_G2::zero()) + // p is not an element of the group (has wrong order) + return {false, bytes()}; + if (p.is_zero() || g1.is_zero()) + continue; // the pairing is one + x = x * libff::alt_bn128_miller_loop( + libff::alt_bn128_precompute_G1(g1), + libff::alt_bn128_precompute_G2(p) + ); + } + bool const result = libff::alt_bn128_final_exponentiation(x) == libff::alt_bn128_GT::one(); + return {true, h256{result}.asBytes()}; + } + catch (InvalidEncoding const&) + { + // Signal the call failure for invalid input. + return {false, bytes{}}; + } +} + +pair dev::crypto::alt_bn128_G1_add(dev::bytesConstRef _in) +{ + try + { + initLibSnark(); + libff::alt_bn128_G1 const p1 = decodePointG1(_in); + libff::alt_bn128_G1 const p2 = decodePointG1(_in.cropped(32 * 2)); + return {true, encodePointG1(p1 + p2)}; + } + catch (InvalidEncoding const&) + { + // Signal the call failure for invalid input. + return {false, bytes{}}; + } +} + +pair dev::crypto::alt_bn128_G1_mul(dev::bytesConstRef _in) +{ + try + { + initLibSnark(); + libff::alt_bn128_G1 const p = decodePointG1(_in.cropped(0)); + libff::alt_bn128_G1 const result = toLibsnarkBigint(h256(_in.cropped(64), h256::AlignLeft)) * p; + return {true, encodePointG1(result)}; + } + catch (InvalidEncoding const&) + { + // Signal the call failure for invalid input. + return {false, bytes{}}; + } +} diff --git a/src/eth_client/libdevcrypto/LibSnark.h b/src/eth_client/libdevcrypto/LibSnark.h new file mode 100644 index 0000000000..15bbc41103 --- /dev/null +++ b/src/eth_client/libdevcrypto/LibSnark.h @@ -0,0 +1,20 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include + +namespace dev +{ +namespace crypto +{ + +std::pair alt_bn128_pairing_product(bytesConstRef _in); +std::pair alt_bn128_G1_add(bytesConstRef _in); +std::pair alt_bn128_G1_mul(bytesConstRef _in); + +} +} diff --git a/src/eth_client/libethashseal/GenesisInfo.cpp b/src/eth_client/libethashseal/GenesisInfo.cpp new file mode 100644 index 0000000000..9fad92b311 --- /dev/null +++ b/src/eth_client/libethashseal/GenesisInfo.cpp @@ -0,0 +1,53 @@ + +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "GenesisInfo.h" +#include +using namespace dev; + +//Client configurations +#include "genesis/qtumNetwork.cpp" + +std::string const& dev::eth::genesisInfo(Network _n) +{ + switch (_n) + { + //Client genesis + case Network::qtumNetwork: return c_genesisInfoQtumNetwork; + + default: + throw std::invalid_argument("Invalid network value"); + } +} + +h256 const& dev::eth::genesisStateRoot(Network _n) +{ + switch (_n) + { + case Network::qtumNetwork: return c_genesisStateRootQtumNetwork; + default: + throw std::invalid_argument("Invalid network value"); + } +} + +void ReplaceInt(uint64_t number, const std::string& key, std::string& str) +{ + // Convert the number into hex string + std::string num_hex = dev::toHexPrefixed(dev::toCompactBigEndian(number)); + + // Search for key in str and replace it with the hex string + std::string str_replaced = std::regex_replace(str, std::regex(key), num_hex); + str = str_replaced; +} + +std::string dev::eth::genesisInfoQtum(Network _n, EVMConsensus _consensus) +{ + std::string _genesisInfo = dev::eth::genesisInfo(_n); + ReplaceInt(_consensus.QIP6Height, "QIP6_STARTING_BLOCK", _genesisInfo); + ReplaceInt(_consensus.QIP7Height, "QIP7_STARTING_BLOCK", _genesisInfo); + ReplaceInt(_consensus.nMuirGlacierHeight, "MUIR_STARTING_BLOCK", _genesisInfo); + ReplaceInt(_consensus.nLondonHeight, "LONDON_STARTING_BLOCK", _genesisInfo); + ReplaceInt(_consensus.nShanghaiHeight, "SHANGHAI_STARTING_BLOCK", _genesisInfo); + return _genesisInfo; +} diff --git a/src/eth_client/libethashseal/GenesisInfo.h b/src/eth_client/libethashseal/GenesisInfo.h new file mode 100644 index 0000000000..0217703b9a --- /dev/null +++ b/src/eth_client/libethashseal/GenesisInfo.h @@ -0,0 +1,53 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include +#include + +namespace dev +{ +namespace eth +{ + +/// The network id. +enum class Network +{ + qtumNetwork = 1 +}; + +std::string const& genesisInfo(Network _n); +h256 const& genesisStateRoot(Network _n); + +/// Set the improvements activation blocks for Qtum +struct EVMConsensus +{ + EVMConsensus() {} + EVMConsensus(int nHeight) : + QIP6Height(nHeight), + QIP7Height(nHeight), + nMuirGlacierHeight(nHeight), + nLondonHeight(nHeight), + nShanghaiHeight(nHeight) + {} + + int QIP6Height = 0x7fffffff; + int QIP7Height = 0x7fffffff; + int nMuirGlacierHeight = 0x7fffffff; + int nLondonHeight = 0x7fffffff; + int nShanghaiHeight = 0x7fffffff; +}; + +/** + * @brief genesisInfoQtum Get the genesis information for EVM + * @param _n Network type + * @param _consensus Qtum network consensus parameters (mainnet, testnet, signet or regtest parameters) + * @return Genesis information for EVM + */ +std::string genesisInfoQtum(Network _n, EVMConsensus _consensus); + +} +} diff --git a/src/eth_client/libethashseal/genesis/qtumNetwork.cpp b/src/eth_client/libethashseal/genesis/qtumNetwork.cpp new file mode 100644 index 0000000000..a9aec30cba --- /dev/null +++ b/src/eth_client/libethashseal/genesis/qtumNetwork.cpp @@ -0,0 +1,79 @@ +/* + 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 . +*/ +#include "../GenesisInfo.h" + +static dev::h256 const c_genesisStateRootQtumNetwork("2ebd2f054ed409f4bc77921ce642517eb574470c01772dc26658d016a4ccc825"); +static std::string const c_genesisInfoQtumNetwork = std::string() + +R"E( +{ + "sealEngine": "NoProof", + "params": { + "accountStartNonce": "0x00", + "homesteadForkBlock": "0x00", + "daoHardforkBlock": "0xfffffffffffffff", + "EIP150ForkBlock": "0x00", + "EIP158ForkBlock": "0x00", + "byzantiumForkBlock": "QIP7_STARTING_BLOCK", + "constantinopleForkBlock": "QIP7_STARTING_BLOCK", + "constantinopleFixForkBlock": "QIP7_STARTING_BLOCK", + "istanbulForkBlock": "MUIR_STARTING_BLOCK", + "muirGlacierForkBlock": "MUIR_STARTING_BLOCK", + "qip6ForkBlock": "QIP6_STARTING_BLOCK", + "berlinForkBlock": "LONDON_STARTING_BLOCK", + "londonForkBlock": "LONDON_STARTING_BLOCK", + "shanghaiForkBlock": "SHANGHAI_STARTING_BLOCK", + "networkID" : "0x51", + "chainID": "0x51", + "maximumExtraDataSize": "0x20", + "tieBreakingGas": false, + "minGasLimit": "0x1388", + "maxGasLimit": "7fffffffffffffff", + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000" + }, + "genesis": { + "nonce": "0x0000000000000042", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x5174756d4d61696e4e6574c9987fd35877cdbbbb84ffeb5315ab1f86c21398c0", + "gasLimit": "0x1388" + }, + "accounts": { + "0000000000000000000000000000000000000080": { "code": + "0x60606040523615610110576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c83ebac14610115578063153417471461017b57806319971cbd146101d85780631ec28e0f146101fe57806327e357461461022f5780633a32306c146102525780634364725c146102ba5780634afb4f11146102eb5780634cc0e2bc146103535780635f302e8b1461038f5780636b102c49146103cd5780636fb81cbb146104185780637b993bf314610427578063850d9758146104725780638a5a9d07146104f2578063bec171e514610523578063bf5f1e831461058b578063e9944a81146105c7578063f769ac4814610652578063f9f51401146106af575b610000565b34610000576101396004808035906020019091908035906020019091905050610738565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b346100005761019660048080359060200190919050506107ee565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576101fc600480803590602001909190803590602001909190505061083a565b005b34610000576102196004808035906020019091905050610f01565b6040518082815260200191505060405180910390f35b346100005761023c610f59565b6040518082815260200191505060405180910390f35b34610000576102a4600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610f67565b6040518082815260200191505060405180910390f35b34610000576102d56004808035906020019091905050610fd5565b6040518082815260200191505060405180910390f35b346100005761033d600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611007565b6040518082815260200191505060405180910390f35b346100005761038d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061109a565b005b34610000576103b36004808035906020019091908035906020019091905050611881565b604051808215151515815260200191505060405180910390f35b34610000576103fe600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611948565b604051808215151515815260200191505060405180910390f35b34610000576104256119ec565b005b3461000057610458600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611ac0565b604051808215151515815260200191505060405180910390f35b346100005761048d6004808035906020019091905050611b64565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146104df575b8051825260208311156104df576020820191506020810190506020830392506104bb565b5050509050019250505060405180910390f35b346100005761050d6004808035906020019091905050611cb7565b6040518082815260200191505060405180910390f35b3461000057610575600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611ce3565b6040518082815260200191505060405180910390f35b34610000576105c5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050611d76565b005b3461000057610638600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919050506129a6565b604051808215151515815260200191505060405180910390f35b346100005761066d6004808035906020019091905050612a23565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576106d36004808035906020019091908035906020019091905050612b55565b6040518080602001828103825283818151815260200191508051906020019060200280838360008314610725575b80518252602083111561072557602082019150602081019050602083039250610701565b5050509050019250505060405180910390f35b600060018311806107495750600282115b1561075357610000565b600083141561079d576006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b60018314156107e7576006600201600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b5b92915050565b6000600082815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b919050565b61084333611948565b151561084e57610000565b600281111561085c57610000565b600081148061086b5750600281145b8015610904575061090160018054806020026020016040519081016040528092919081815260200182805480156108f757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116108ad575b5050505050610f67565b82115b1561090e57610000565b6001811480156109ab57506109a8600280548060200260200160405190810160405280929190818152602001828054801561099e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610954575b5050505050610f67565b82115b156109b557610000565b60008114156109d1578160096000015414156109d057610000565b5b60018114156109ed578160096001015414156109ec57610000565b5b6002811415610a0957816009600201541415610a0857610000565b5b6006600101600082815260200190815260200160002060000160009054906101000a900460ff161515610bbb5760016006600101600083815260200190815260200160002060000160006101000a81548160ff02191690831515021790555081600660010160008381526020019081526020016000206002018190555043600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060010181815481835581811511610aff57818360005260206000209182019101610afe91905b80821115610afa576000816000905550600101610ae2565b5090565b5b50505050600660010160008281526020019081526020016000206001018054806001018281815481835581811511610b6357818360005260206000209182019101610b6291905b80821115610b5e576000816000905550600101610b46565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610d7a565b600554600660010160008381526020019081526020016000206003015443031115610bee57610be981612d90565b610efc565b816006600101600083815260200190815260200160002060020154141515610c1557610000565b610cbc3360066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610cb257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610c68575b50505050506129a6565b15610cc657610000565b600660010160008281526020019081526020016000206001018054806001018281815481835581811511610d2657818360005260206000209182019101610d2591905b80821115610d21576000816000905550600101610d09565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600960020154610e2660066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610e1c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610dd2575b5050505050611ce3565b101515610efb576000811480610e3c5750600181145b15610e4c57610e4b6002612e63565b5b6000811415610e795760066001016000828152602001908152602001600020600201546009600001819055505b6002811415610e9757610e8c6000612e63565b610e966001612e63565b5b6001811415610ec45760066001016000828152602001908152602001600020600201546009600101819055505b6002811415610ef15760066001016000828152602001908152602001600020600201546009600201819055505b610efa81612d90565b5b5b5b5050565b60006002821115610f1157610000565b6000821415610f27576009600001549050610f54565b6001821415610f3d576009600101549050610f54565b6002821415610f53576009600201549050610f54565b5b919050565b600060008054905090505b90565b60006000600060009050600091505b8351821015610fca57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141515610fbc5780806001019150505b5b8180600101925050610f76565b8092505b5050919050565b60006002821115610fe557610000565b600660010160008381526020019081526020016000206002015490505b919050565b60006000600060009050600091505b835182101561108f57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141580156110735750611072848381518110156100005790602001906020020151611ac0565b5b156110815780806001019150505b5b8180600101925050611016565b8092505b5050919050565b600060006110a733611948565b15156110b257610000565b60008473ffffffffffffffffffffffffffffffffffffffff1614156110d657610000565b60018311156110e457610000565b60008314156111b45761117c600180548060200260200160405190810160405280929190818152602001828054801561117257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611128575b5050505050610f67565b9150600960000154821480611195575060096002015482145b1561119f57610000565b6111a884611948565b15156111b357610000565b5b600183141561127257600960010154611252600280548060200260200160405190810160405280929190818152602001828054801561124857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116111fe575b5050505050610f67565b141561125d57610000565b61126684611ac0565b151561127157610000565b5b6006600201600084815260200190815260200160002060000160009054906101000a900460ff16151561145e5760016006600201600085815260200190815260200160002060000160006101000a81548160ff021916908315150217905550836006600201600085815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550436006600201600085815260200190815260200160002060030181905550600060066002016000858152602001908152602001600020600101818154818355818115116113a2578183600052602060002091820191016113a191905b8082111561139d576000816000905550600101611385565b5090565b5b505050506006600201600084815260200190815260200160002060010180548060010182818154818355818115116114065781836000526020600020918201910161140591905b808211156114015760008160009055506001016113e9565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050611669565b6005546006600201600085815260200190815260200160002060030154430311156114915761148c83612f70565b61187a565b8373ffffffffffffffffffffffffffffffffffffffff166006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561150457610000565b6115ab33600660020160008681526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156115a157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611557575b50505050506129a6565b156115b557610000565b6006600201600084815260200190815260200160002060010180548060010182818154818355818115116116155781836000526020600020918201910161161491905b808211156116105760008160009055506001016115f8565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b6009600201546117156006600201600086815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561170b57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116116c1575b5050505050611ce3565b1015156118795760008314801561176a57506117696006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b5b156117b3576117b2836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b60018314801561180157506118006006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b1561184a57611849836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b600090505b600381101561186f5761186181612e63565b5b808060010191505061184f565b61187883612f70565b5b5b5b50505050565b600060028311806118925750600282115b1561189c57610000565b60008314156118d3576006600001600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b600183141561190a576006600101600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b6002831415611941576006600201600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b5b92915050565b60006000600090505b6001805490508110156119e1578273ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156119d357600191506119e6565b5b8080600101915050611951565b600091505b50919050565b600460009054906101000a900460ff1615611a0657610000565b60018054806001018281815481835581811511611a4f57818360005260206000209182019101611a4e91905b80821115611a4a576000816000905550600101611a32565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506001600460006101000a81548160ff0219169083151502179055505b565b60006000600090505b600280549050811015611b59578273ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415611b4b5760019150611b5e565b5b8080600101915050611ac9565b600091505b50919050565b60206040519081016040528060008152506001821115611b8357610000565b6000821415611c1a576001805480602002602001604051908101604052809291908181526020018280548015611c0e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611bc4575b50505050509050611cb2565b6001821415611cb1576002805480602002602001604051908101604052809291908181526020018280548015611ca557602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611c5b575b50505050509050611cb2565b5b919050565b6000600082815481101561000057906000526020600020906002020160005b506000015490505b919050565b60006000600060009050600091505b8351821015611d6b57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff1614158015611d4f5750611d4e848381518110156100005790602001906020020151611948565b5b15611d5d5780806001019150505b5b8180600101925050611cf2565b8092505b5050919050565b611d7f33611948565b158015611d925750611d9033611ac0565b155b15611d9c57610000565b600081148015611e3c5750600354611e396001805480602002602001604051908101604052809291908181526020018280548015611e2f57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611de5575b5050505050610f67565b10155b15611e4657610000565b600181148015611ee65750600354611ee36002805480602002602001604051908101604052809291908181526020018280548015611ed957602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611e8f575b5050505050610f67565b10155b15611ef057610000565b60008273ffffffffffffffffffffffffffffffffffffffff161415611f1457610000565b6002811115611f2257610000565b6000811480611f315750600181145b8015611f525750611f4182611948565b80611f515750611f5082611ac0565b5b5b15611f5c57610000565b6006600001600082815260200190815260200160002060000160009054906101000a900460ff16151561215b57611f9233611ac0565b15611f9c57610000565b60016006600001600083815260200190815260200160002060000160006101000a81548160ff021916908315150217905550816006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504360066000016000838152602001908152602001600020600301819055506000600660000160008381526020019081526020016000206001018181548183558181151161209f5781836000526020600020918201910161209e91905b8082111561209a576000816000905550600101612082565b5090565b5b505050506006600001600082815260200190815260200160002060010180548060010182818154818355818115116121035781836000526020600020918201910161210291905b808211156120fe5760008160009055506001016120e6565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050612366565b60055460066000016000838152602001908152602001600020600301544303111561218e5761218981612e63565b6129a1565b8173ffffffffffffffffffffffffffffffffffffffff166006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561220157610000565b6122a8336006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561229e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612254575b50505050506129a6565b156122b257610000565b6006600001600082815260200190815260200160002060010180548060010182818154818355818115116123125781836000526020600020918201910161231191905b8082111561230d5760008160009055506001016122f5565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b60008114806123755750600181145b1561268b576009600201546124266006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561241c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116123d2575b5050505050611ce3565b10151561268a5761246f6006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b806124b857506124b76006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b156124c257610000565b60008114156125a157600180548060010182818154818355818115116125145781836000526020600020918201910161251391905b8082111561250f5760008160009055506001016124f7565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600181141561268057600280548060010182818154818355818115116125f3578183600052602060002091820191016125f291905b808211156125ee5760008160009055506001016125d6565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b61268981612e63565b5b5b60028114156129a0576009600001546127406006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561273657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116126ec575b5050505050611ce3565b101580156127f857506009600101546127f5600660000160008481526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156127eb57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116127a1575b5050505050611007565b10155b1561299f57600060008054905011801561283d5750600143016000600160008054905003815481101561000057906000526020600020906002020160005b5060000154145b1561284757610000565b600080548060010182818154818355818115116128c0576002028160020283600052602060002091820191016128bf91905b808211156128bb57600060008201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600201612879565b5090565b5b505050916000526020600020906002020160005b6040604051908101604052806001430181526020016006600001600087815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525090919091506000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505061299e81612e63565b5b5b5b5b5050565b60006000600090505b8251811015612a17578373ffffffffffffffffffffffffffffffffffffffff1683828151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff161415612a095760019150612a1c565b5b80806001019150506129af565b600091505b5092915050565b6000600060006000805490501415612a3e5760009150612b4f565b60016000805490500390505b6000811115612ad55782600082815481101561000057906000526020600020906002020160005b5060000154111515612ac657600081815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b5b808060019003915050612a4a565b8260006000815481101561000057906000526020600020906002020160005b5060000154111515612b4a5760006000815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b600091505b50919050565b60206040519081016040528060008152506002831180612b755750600282115b15612b7f57610000565b6000831415612c2d5760066000016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612c2157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612bd7575b50505050509050612d8a565b6001831415612cdb5760066001016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612ccf57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612c85575b50505050509050612d8a565b6002831415612d895760066002016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612d7d57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612d33575b50505050509050612d8a565b5b92915050565b6000600660010160008381526020019081526020016000206002018190555060006006600101600083815260200190815260200160002060010181815481835581811511612e0a57818360005260206000209182019101612e0991905b80821115612e05576000816000905550600101612ded565b5090565b5b505050506000600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060006006600001600083815260200190815260200160002060010181815481835581811511612f1757818360005260206000209182019101612f1691905b80821115612f12576000816000905550600101612efa565b5090565b5b505050506000600660000160008381526020019081526020016000206003018190555060006006600001600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600201600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060066002016000838152602001908152602001600020600101818154818355818115116130245781836000526020600020918201910161302391905b8082111561301f576000816000905550600101613007565b5090565b5b505050506000600660020160008381526020019081526020016000206003018190555060006006600201600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b6000600083141561315157600090505b600180549050811015613150578173ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561314257600181815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061308d565b5b600183141561322357600090505b600280549050811015613222578173ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561321457600281815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061315f565b5b5b5050505600a165627a7a7230582036e4abcf6c2808d63bc7a088f625291c4621d5f8e2812de8b45d7456f787eac00029", + "storage": {"3": "30","5": "21600"} }, + "0000000000000000000000000000000000000081": { "code": + "0x60606040523615610110576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c83ebac14610115578063153417471461017b57806319971cbd146101d85780631ec28e0f146101fe57806327e357461461022f5780633a32306c146102525780634364725c146102ba5780634afb4f11146102eb5780634cc0e2bc146103535780635f302e8b1461038f5780636b102c49146103cd5780636fb81cbb146104185780637b993bf314610427578063850d9758146104725780638a5a9d07146104f2578063bec171e514610523578063bf5f1e831461058b578063e9944a81146105c7578063f769ac4814610652578063f9f51401146106af575b610000565b34610000576101396004808035906020019091908035906020019091905050610738565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b346100005761019660048080359060200190919050506107ee565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576101fc600480803590602001909190803590602001909190505061083a565b005b34610000576102196004808035906020019091905050610f01565b6040518082815260200191505060405180910390f35b346100005761023c610f59565b6040518082815260200191505060405180910390f35b34610000576102a4600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610f67565b6040518082815260200191505060405180910390f35b34610000576102d56004808035906020019091905050610fd5565b6040518082815260200191505060405180910390f35b346100005761033d600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611007565b6040518082815260200191505060405180910390f35b346100005761038d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061109a565b005b34610000576103b36004808035906020019091908035906020019091905050611881565b604051808215151515815260200191505060405180910390f35b34610000576103fe600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611948565b604051808215151515815260200191505060405180910390f35b34610000576104256119ec565b005b3461000057610458600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611ac0565b604051808215151515815260200191505060405180910390f35b346100005761048d6004808035906020019091905050611b64565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146104df575b8051825260208311156104df576020820191506020810190506020830392506104bb565b5050509050019250505060405180910390f35b346100005761050d6004808035906020019091905050611cb7565b6040518082815260200191505060405180910390f35b3461000057610575600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611ce3565b6040518082815260200191505060405180910390f35b34610000576105c5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050611d76565b005b3461000057610638600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919050506129a6565b604051808215151515815260200191505060405180910390f35b346100005761066d6004808035906020019091905050612a23565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576106d36004808035906020019091908035906020019091905050612b55565b6040518080602001828103825283818151815260200191508051906020019060200280838360008314610725575b80518252602083111561072557602082019150602081019050602083039250610701565b5050509050019250505060405180910390f35b600060018311806107495750600282115b1561075357610000565b600083141561079d576006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b60018314156107e7576006600201600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b5b92915050565b6000600082815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b919050565b61084333611948565b151561084e57610000565b600281111561085c57610000565b600081148061086b5750600281145b8015610904575061090160018054806020026020016040519081016040528092919081815260200182805480156108f757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116108ad575b5050505050610f67565b82115b1561090e57610000565b6001811480156109ab57506109a8600280548060200260200160405190810160405280929190818152602001828054801561099e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610954575b5050505050610f67565b82115b156109b557610000565b60008114156109d1578160096000015414156109d057610000565b5b60018114156109ed578160096001015414156109ec57610000565b5b6002811415610a0957816009600201541415610a0857610000565b5b6006600101600082815260200190815260200160002060000160009054906101000a900460ff161515610bbb5760016006600101600083815260200190815260200160002060000160006101000a81548160ff02191690831515021790555081600660010160008381526020019081526020016000206002018190555043600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060010181815481835581811511610aff57818360005260206000209182019101610afe91905b80821115610afa576000816000905550600101610ae2565b5090565b5b50505050600660010160008281526020019081526020016000206001018054806001018281815481835581811511610b6357818360005260206000209182019101610b6291905b80821115610b5e576000816000905550600101610b46565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610d7a565b600554600660010160008381526020019081526020016000206003015443031115610bee57610be981612d90565b610efc565b816006600101600083815260200190815260200160002060020154141515610c1557610000565b610cbc3360066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610cb257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610c68575b50505050506129a6565b15610cc657610000565b600660010160008281526020019081526020016000206001018054806001018281815481835581811511610d2657818360005260206000209182019101610d2591905b80821115610d21576000816000905550600101610d09565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600960020154610e2660066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610e1c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610dd2575b5050505050611ce3565b101515610efb576000811480610e3c5750600181145b15610e4c57610e4b6002612e63565b5b6000811415610e795760066001016000828152602001908152602001600020600201546009600001819055505b6002811415610e9757610e8c6000612e63565b610e966001612e63565b5b6001811415610ec45760066001016000828152602001908152602001600020600201546009600101819055505b6002811415610ef15760066001016000828152602001908152602001600020600201546009600201819055505b610efa81612d90565b5b5b5b5050565b60006002821115610f1157610000565b6000821415610f27576009600001549050610f54565b6001821415610f3d576009600101549050610f54565b6002821415610f53576009600201549050610f54565b5b919050565b600060008054905090505b90565b60006000600060009050600091505b8351821015610fca57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141515610fbc5780806001019150505b5b8180600101925050610f76565b8092505b5050919050565b60006002821115610fe557610000565b600660010160008381526020019081526020016000206002015490505b919050565b60006000600060009050600091505b835182101561108f57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141580156110735750611072848381518110156100005790602001906020020151611ac0565b5b156110815780806001019150505b5b8180600101925050611016565b8092505b5050919050565b600060006110a733611948565b15156110b257610000565b60008473ffffffffffffffffffffffffffffffffffffffff1614156110d657610000565b60018311156110e457610000565b60008314156111b45761117c600180548060200260200160405190810160405280929190818152602001828054801561117257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611128575b5050505050610f67565b9150600960000154821480611195575060096002015482145b1561119f57610000565b6111a884611948565b15156111b357610000565b5b600183141561127257600960010154611252600280548060200260200160405190810160405280929190818152602001828054801561124857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116111fe575b5050505050610f67565b141561125d57610000565b61126684611ac0565b151561127157610000565b5b6006600201600084815260200190815260200160002060000160009054906101000a900460ff16151561145e5760016006600201600085815260200190815260200160002060000160006101000a81548160ff021916908315150217905550836006600201600085815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550436006600201600085815260200190815260200160002060030181905550600060066002016000858152602001908152602001600020600101818154818355818115116113a2578183600052602060002091820191016113a191905b8082111561139d576000816000905550600101611385565b5090565b5b505050506006600201600084815260200190815260200160002060010180548060010182818154818355818115116114065781836000526020600020918201910161140591905b808211156114015760008160009055506001016113e9565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050611669565b6005546006600201600085815260200190815260200160002060030154430311156114915761148c83612f70565b61187a565b8373ffffffffffffffffffffffffffffffffffffffff166006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561150457610000565b6115ab33600660020160008681526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156115a157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611557575b50505050506129a6565b156115b557610000565b6006600201600084815260200190815260200160002060010180548060010182818154818355818115116116155781836000526020600020918201910161161491905b808211156116105760008160009055506001016115f8565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b6009600201546117156006600201600086815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561170b57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116116c1575b5050505050611ce3565b1015156118795760008314801561176a57506117696006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b5b156117b3576117b2836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b60018314801561180157506118006006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b1561184a57611849836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b600090505b600381101561186f5761186181612e63565b5b808060010191505061184f565b61187883612f70565b5b5b5b50505050565b600060028311806118925750600282115b1561189c57610000565b60008314156118d3576006600001600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b600183141561190a576006600101600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b6002831415611941576006600201600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b5b92915050565b60006000600090505b6001805490508110156119e1578273ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156119d357600191506119e6565b5b8080600101915050611951565b600091505b50919050565b600460009054906101000a900460ff1615611a0657610000565b60018054806001018281815481835581811511611a4f57818360005260206000209182019101611a4e91905b80821115611a4a576000816000905550600101611a32565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506001600460006101000a81548160ff0219169083151502179055505b565b60006000600090505b600280549050811015611b59578273ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415611b4b5760019150611b5e565b5b8080600101915050611ac9565b600091505b50919050565b60206040519081016040528060008152506001821115611b8357610000565b6000821415611c1a576001805480602002602001604051908101604052809291908181526020018280548015611c0e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611bc4575b50505050509050611cb2565b6001821415611cb1576002805480602002602001604051908101604052809291908181526020018280548015611ca557602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611c5b575b50505050509050611cb2565b5b919050565b6000600082815481101561000057906000526020600020906002020160005b506000015490505b919050565b60006000600060009050600091505b8351821015611d6b57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff1614158015611d4f5750611d4e848381518110156100005790602001906020020151611948565b5b15611d5d5780806001019150505b5b8180600101925050611cf2565b8092505b5050919050565b611d7f33611948565b158015611d925750611d9033611ac0565b155b15611d9c57610000565b600081148015611e3c5750600354611e396001805480602002602001604051908101604052809291908181526020018280548015611e2f57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611de5575b5050505050610f67565b10155b15611e4657610000565b600181148015611ee65750600354611ee36002805480602002602001604051908101604052809291908181526020018280548015611ed957602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611e8f575b5050505050610f67565b10155b15611ef057610000565b60008273ffffffffffffffffffffffffffffffffffffffff161415611f1457610000565b6002811115611f2257610000565b6000811480611f315750600181145b8015611f525750611f4182611948565b80611f515750611f5082611ac0565b5b5b15611f5c57610000565b6006600001600082815260200190815260200160002060000160009054906101000a900460ff16151561215b57611f9233611ac0565b15611f9c57610000565b60016006600001600083815260200190815260200160002060000160006101000a81548160ff021916908315150217905550816006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504360066000016000838152602001908152602001600020600301819055506000600660000160008381526020019081526020016000206001018181548183558181151161209f5781836000526020600020918201910161209e91905b8082111561209a576000816000905550600101612082565b5090565b5b505050506006600001600082815260200190815260200160002060010180548060010182818154818355818115116121035781836000526020600020918201910161210291905b808211156120fe5760008160009055506001016120e6565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050612366565b60055460066000016000838152602001908152602001600020600301544303111561218e5761218981612e63565b6129a1565b8173ffffffffffffffffffffffffffffffffffffffff166006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561220157610000565b6122a8336006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561229e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612254575b50505050506129a6565b156122b257610000565b6006600001600082815260200190815260200160002060010180548060010182818154818355818115116123125781836000526020600020918201910161231191905b8082111561230d5760008160009055506001016122f5565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b60008114806123755750600181145b1561268b576009600201546124266006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561241c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116123d2575b5050505050611ce3565b10151561268a5761246f6006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b806124b857506124b76006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b156124c257610000565b60008114156125a157600180548060010182818154818355818115116125145781836000526020600020918201910161251391905b8082111561250f5760008160009055506001016124f7565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600181141561268057600280548060010182818154818355818115116125f3578183600052602060002091820191016125f291905b808211156125ee5760008160009055506001016125d6565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b61268981612e63565b5b5b60028114156129a0576009600001546127406006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561273657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116126ec575b5050505050611ce3565b101580156127f857506009600101546127f5600660000160008481526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156127eb57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116127a1575b5050505050611007565b10155b1561299f57600060008054905011801561283d5750600143016000600160008054905003815481101561000057906000526020600020906002020160005b5060000154145b1561284757610000565b600080548060010182818154818355818115116128c0576002028160020283600052602060002091820191016128bf91905b808211156128bb57600060008201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600201612879565b5090565b5b505050916000526020600020906002020160005b6040604051908101604052806001430181526020016006600001600087815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525090919091506000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505061299e81612e63565b5b5b5b5b5050565b60006000600090505b8251811015612a17578373ffffffffffffffffffffffffffffffffffffffff1683828151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff161415612a095760019150612a1c565b5b80806001019150506129af565b600091505b5092915050565b6000600060006000805490501415612a3e5760009150612b4f565b60016000805490500390505b6000811115612ad55782600082815481101561000057906000526020600020906002020160005b5060000154111515612ac657600081815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b5b808060019003915050612a4a565b8260006000815481101561000057906000526020600020906002020160005b5060000154111515612b4a5760006000815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b600091505b50919050565b60206040519081016040528060008152506002831180612b755750600282115b15612b7f57610000565b6000831415612c2d5760066000016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612c2157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612bd7575b50505050509050612d8a565b6001831415612cdb5760066001016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612ccf57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612c85575b50505050509050612d8a565b6002831415612d895760066002016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612d7d57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612d33575b50505050509050612d8a565b5b92915050565b6000600660010160008381526020019081526020016000206002018190555060006006600101600083815260200190815260200160002060010181815481835581811511612e0a57818360005260206000209182019101612e0991905b80821115612e05576000816000905550600101612ded565b5090565b5b505050506000600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060006006600001600083815260200190815260200160002060010181815481835581811511612f1757818360005260206000209182019101612f1691905b80821115612f12576000816000905550600101612efa565b5090565b5b505050506000600660000160008381526020019081526020016000206003018190555060006006600001600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600201600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060066002016000838152602001908152602001600020600101818154818355818115116130245781836000526020600020918201910161302391905b8082111561301f576000816000905550600101613007565b5090565b5b505050506000600660020160008381526020019081526020016000206003018190555060006006600201600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b6000600083141561315157600090505b600180549050811015613150578173ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561314257600181815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061308d565b5b600183141561322357600090505b600280549050811015613222578173ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561321457600281815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061315f565b5b5b5050505600a165627a7a7230582036e4abcf6c2808d63bc7a088f625291c4621d5f8e2812de8b45d7456f787eac00029", + "storage": {"3": "30","5": "21600"} }, + "0000000000000000000000000000000000000082": { "code": + "0x60606040523615610110576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c83ebac14610115578063153417471461017b57806319971cbd146101d85780631ec28e0f146101fe57806327e357461461022f5780633a32306c146102525780634364725c146102ba5780634afb4f11146102eb5780634cc0e2bc146103535780635f302e8b1461038f5780636b102c49146103cd5780636fb81cbb146104185780637b993bf314610427578063850d9758146104725780638a5a9d07146104f2578063bec171e514610523578063bf5f1e831461058b578063e9944a81146105c7578063f769ac4814610652578063f9f51401146106af575b610000565b34610000576101396004808035906020019091908035906020019091905050610738565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b346100005761019660048080359060200190919050506107ee565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576101fc600480803590602001909190803590602001909190505061083a565b005b34610000576102196004808035906020019091905050610f01565b6040518082815260200191505060405180910390f35b346100005761023c610f59565b6040518082815260200191505060405180910390f35b34610000576102a4600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610f67565b6040518082815260200191505060405180910390f35b34610000576102d56004808035906020019091905050610fd5565b6040518082815260200191505060405180910390f35b346100005761033d600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611007565b6040518082815260200191505060405180910390f35b346100005761038d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061109a565b005b34610000576103b36004808035906020019091908035906020019091905050611881565b604051808215151515815260200191505060405180910390f35b34610000576103fe600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611948565b604051808215151515815260200191505060405180910390f35b34610000576104256119ec565b005b3461000057610458600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611ac0565b604051808215151515815260200191505060405180910390f35b346100005761048d6004808035906020019091905050611b64565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146104df575b8051825260208311156104df576020820191506020810190506020830392506104bb565b5050509050019250505060405180910390f35b346100005761050d6004808035906020019091905050611cb7565b6040518082815260200191505060405180910390f35b3461000057610575600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611ce3565b6040518082815260200191505060405180910390f35b34610000576105c5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050611d76565b005b3461000057610638600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919050506129a6565b604051808215151515815260200191505060405180910390f35b346100005761066d6004808035906020019091905050612a23565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576106d36004808035906020019091908035906020019091905050612b55565b6040518080602001828103825283818151815260200191508051906020019060200280838360008314610725575b80518252602083111561072557602082019150602081019050602083039250610701565b5050509050019250505060405180910390f35b600060018311806107495750600282115b1561075357610000565b600083141561079d576006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b60018314156107e7576006600201600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b5b92915050565b6000600082815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b919050565b61084333611948565b151561084e57610000565b600281111561085c57610000565b600081148061086b5750600281145b8015610904575061090160018054806020026020016040519081016040528092919081815260200182805480156108f757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116108ad575b5050505050610f67565b82115b1561090e57610000565b6001811480156109ab57506109a8600280548060200260200160405190810160405280929190818152602001828054801561099e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610954575b5050505050610f67565b82115b156109b557610000565b60008114156109d1578160096000015414156109d057610000565b5b60018114156109ed578160096001015414156109ec57610000565b5b6002811415610a0957816009600201541415610a0857610000565b5b6006600101600082815260200190815260200160002060000160009054906101000a900460ff161515610bbb5760016006600101600083815260200190815260200160002060000160006101000a81548160ff02191690831515021790555081600660010160008381526020019081526020016000206002018190555043600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060010181815481835581811511610aff57818360005260206000209182019101610afe91905b80821115610afa576000816000905550600101610ae2565b5090565b5b50505050600660010160008281526020019081526020016000206001018054806001018281815481835581811511610b6357818360005260206000209182019101610b6291905b80821115610b5e576000816000905550600101610b46565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610d7a565b600554600660010160008381526020019081526020016000206003015443031115610bee57610be981612d90565b610efc565b816006600101600083815260200190815260200160002060020154141515610c1557610000565b610cbc3360066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610cb257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610c68575b50505050506129a6565b15610cc657610000565b600660010160008281526020019081526020016000206001018054806001018281815481835581811511610d2657818360005260206000209182019101610d2591905b80821115610d21576000816000905550600101610d09565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600960020154610e2660066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610e1c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610dd2575b5050505050611ce3565b101515610efb576000811480610e3c5750600181145b15610e4c57610e4b6002612e63565b5b6000811415610e795760066001016000828152602001908152602001600020600201546009600001819055505b6002811415610e9757610e8c6000612e63565b610e966001612e63565b5b6001811415610ec45760066001016000828152602001908152602001600020600201546009600101819055505b6002811415610ef15760066001016000828152602001908152602001600020600201546009600201819055505b610efa81612d90565b5b5b5b5050565b60006002821115610f1157610000565b6000821415610f27576009600001549050610f54565b6001821415610f3d576009600101549050610f54565b6002821415610f53576009600201549050610f54565b5b919050565b600060008054905090505b90565b60006000600060009050600091505b8351821015610fca57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141515610fbc5780806001019150505b5b8180600101925050610f76565b8092505b5050919050565b60006002821115610fe557610000565b600660010160008381526020019081526020016000206002015490505b919050565b60006000600060009050600091505b835182101561108f57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141580156110735750611072848381518110156100005790602001906020020151611ac0565b5b156110815780806001019150505b5b8180600101925050611016565b8092505b5050919050565b600060006110a733611948565b15156110b257610000565b60008473ffffffffffffffffffffffffffffffffffffffff1614156110d657610000565b60018311156110e457610000565b60008314156111b45761117c600180548060200260200160405190810160405280929190818152602001828054801561117257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611128575b5050505050610f67565b9150600960000154821480611195575060096002015482145b1561119f57610000565b6111a884611948565b15156111b357610000565b5b600183141561127257600960010154611252600280548060200260200160405190810160405280929190818152602001828054801561124857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116111fe575b5050505050610f67565b141561125d57610000565b61126684611ac0565b151561127157610000565b5b6006600201600084815260200190815260200160002060000160009054906101000a900460ff16151561145e5760016006600201600085815260200190815260200160002060000160006101000a81548160ff021916908315150217905550836006600201600085815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550436006600201600085815260200190815260200160002060030181905550600060066002016000858152602001908152602001600020600101818154818355818115116113a2578183600052602060002091820191016113a191905b8082111561139d576000816000905550600101611385565b5090565b5b505050506006600201600084815260200190815260200160002060010180548060010182818154818355818115116114065781836000526020600020918201910161140591905b808211156114015760008160009055506001016113e9565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050611669565b6005546006600201600085815260200190815260200160002060030154430311156114915761148c83612f70565b61187a565b8373ffffffffffffffffffffffffffffffffffffffff166006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561150457610000565b6115ab33600660020160008681526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156115a157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611557575b50505050506129a6565b156115b557610000565b6006600201600084815260200190815260200160002060010180548060010182818154818355818115116116155781836000526020600020918201910161161491905b808211156116105760008160009055506001016115f8565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b6009600201546117156006600201600086815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561170b57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116116c1575b5050505050611ce3565b1015156118795760008314801561176a57506117696006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b5b156117b3576117b2836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b60018314801561180157506118006006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b1561184a57611849836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b600090505b600381101561186f5761186181612e63565b5b808060010191505061184f565b61187883612f70565b5b5b5b50505050565b600060028311806118925750600282115b1561189c57610000565b60008314156118d3576006600001600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b600183141561190a576006600101600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b6002831415611941576006600201600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b5b92915050565b60006000600090505b6001805490508110156119e1578273ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156119d357600191506119e6565b5b8080600101915050611951565b600091505b50919050565b600460009054906101000a900460ff1615611a0657610000565b60018054806001018281815481835581811511611a4f57818360005260206000209182019101611a4e91905b80821115611a4a576000816000905550600101611a32565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506001600460006101000a81548160ff0219169083151502179055505b565b60006000600090505b600280549050811015611b59578273ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415611b4b5760019150611b5e565b5b8080600101915050611ac9565b600091505b50919050565b60206040519081016040528060008152506001821115611b8357610000565b6000821415611c1a576001805480602002602001604051908101604052809291908181526020018280548015611c0e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611bc4575b50505050509050611cb2565b6001821415611cb1576002805480602002602001604051908101604052809291908181526020018280548015611ca557602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611c5b575b50505050509050611cb2565b5b919050565b6000600082815481101561000057906000526020600020906002020160005b506000015490505b919050565b60006000600060009050600091505b8351821015611d6b57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff1614158015611d4f5750611d4e848381518110156100005790602001906020020151611948565b5b15611d5d5780806001019150505b5b8180600101925050611cf2565b8092505b5050919050565b611d7f33611948565b158015611d925750611d9033611ac0565b155b15611d9c57610000565b600081148015611e3c5750600354611e396001805480602002602001604051908101604052809291908181526020018280548015611e2f57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611de5575b5050505050610f67565b10155b15611e4657610000565b600181148015611ee65750600354611ee36002805480602002602001604051908101604052809291908181526020018280548015611ed957602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611e8f575b5050505050610f67565b10155b15611ef057610000565b60008273ffffffffffffffffffffffffffffffffffffffff161415611f1457610000565b6002811115611f2257610000565b6000811480611f315750600181145b8015611f525750611f4182611948565b80611f515750611f5082611ac0565b5b5b15611f5c57610000565b6006600001600082815260200190815260200160002060000160009054906101000a900460ff16151561215b57611f9233611ac0565b15611f9c57610000565b60016006600001600083815260200190815260200160002060000160006101000a81548160ff021916908315150217905550816006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504360066000016000838152602001908152602001600020600301819055506000600660000160008381526020019081526020016000206001018181548183558181151161209f5781836000526020600020918201910161209e91905b8082111561209a576000816000905550600101612082565b5090565b5b505050506006600001600082815260200190815260200160002060010180548060010182818154818355818115116121035781836000526020600020918201910161210291905b808211156120fe5760008160009055506001016120e6565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050612366565b60055460066000016000838152602001908152602001600020600301544303111561218e5761218981612e63565b6129a1565b8173ffffffffffffffffffffffffffffffffffffffff166006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561220157610000565b6122a8336006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561229e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612254575b50505050506129a6565b156122b257610000565b6006600001600082815260200190815260200160002060010180548060010182818154818355818115116123125781836000526020600020918201910161231191905b8082111561230d5760008160009055506001016122f5565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b60008114806123755750600181145b1561268b576009600201546124266006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561241c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116123d2575b5050505050611ce3565b10151561268a5761246f6006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b806124b857506124b76006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b156124c257610000565b60008114156125a157600180548060010182818154818355818115116125145781836000526020600020918201910161251391905b8082111561250f5760008160009055506001016124f7565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600181141561268057600280548060010182818154818355818115116125f3578183600052602060002091820191016125f291905b808211156125ee5760008160009055506001016125d6565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b61268981612e63565b5b5b60028114156129a0576009600001546127406006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561273657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116126ec575b5050505050611ce3565b101580156127f857506009600101546127f5600660000160008481526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156127eb57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116127a1575b5050505050611007565b10155b1561299f57600060008054905011801561283d5750600143016000600160008054905003815481101561000057906000526020600020906002020160005b5060000154145b1561284757610000565b600080548060010182818154818355818115116128c0576002028160020283600052602060002091820191016128bf91905b808211156128bb57600060008201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600201612879565b5090565b5b505050916000526020600020906002020160005b6040604051908101604052806001430181526020016006600001600087815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525090919091506000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505061299e81612e63565b5b5b5b5b5050565b60006000600090505b8251811015612a17578373ffffffffffffffffffffffffffffffffffffffff1683828151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff161415612a095760019150612a1c565b5b80806001019150506129af565b600091505b5092915050565b6000600060006000805490501415612a3e5760009150612b4f565b60016000805490500390505b6000811115612ad55782600082815481101561000057906000526020600020906002020160005b5060000154111515612ac657600081815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b5b808060019003915050612a4a565b8260006000815481101561000057906000526020600020906002020160005b5060000154111515612b4a5760006000815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b600091505b50919050565b60206040519081016040528060008152506002831180612b755750600282115b15612b7f57610000565b6000831415612c2d5760066000016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612c2157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612bd7575b50505050509050612d8a565b6001831415612cdb5760066001016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612ccf57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612c85575b50505050509050612d8a565b6002831415612d895760066002016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612d7d57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612d33575b50505050509050612d8a565b5b92915050565b6000600660010160008381526020019081526020016000206002018190555060006006600101600083815260200190815260200160002060010181815481835581811511612e0a57818360005260206000209182019101612e0991905b80821115612e05576000816000905550600101612ded565b5090565b5b505050506000600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060006006600001600083815260200190815260200160002060010181815481835581811511612f1757818360005260206000209182019101612f1691905b80821115612f12576000816000905550600101612efa565b5090565b5b505050506000600660000160008381526020019081526020016000206003018190555060006006600001600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600201600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060066002016000838152602001908152602001600020600101818154818355818115116130245781836000526020600020918201910161302391905b8082111561301f576000816000905550600101613007565b5090565b5b505050506000600660020160008381526020019081526020016000206003018190555060006006600201600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b6000600083141561315157600090505b600180549050811015613150578173ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561314257600181815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061308d565b5b600183141561322357600090505b600280549050811015613222578173ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561321457600281815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061315f565b5b5b5050505600a165627a7a7230582036e4abcf6c2808d63bc7a088f625291c4621d5f8e2812de8b45d7456f787eac00029", + "storage": {"3": "30","5": "21600"} }, + "0000000000000000000000000000000000000083": { "code": + "0x60606040523615610110576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c83ebac14610115578063153417471461017b57806319971cbd146101d85780631ec28e0f146101fe57806327e357461461022f5780633a32306c146102525780634364725c146102ba5780634afb4f11146102eb5780634cc0e2bc146103535780635f302e8b1461038f5780636b102c49146103cd5780636fb81cbb146104185780637b993bf314610427578063850d9758146104725780638a5a9d07146104f2578063bec171e514610523578063bf5f1e831461058b578063e9944a81146105c7578063f769ac4814610652578063f9f51401146106af575b610000565b34610000576101396004808035906020019091908035906020019091905050610738565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b346100005761019660048080359060200190919050506107ee565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576101fc600480803590602001909190803590602001909190505061083a565b005b34610000576102196004808035906020019091905050610f01565b6040518082815260200191505060405180910390f35b346100005761023c610f59565b6040518082815260200191505060405180910390f35b34610000576102a4600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610f67565b6040518082815260200191505060405180910390f35b34610000576102d56004808035906020019091905050610fd5565b6040518082815260200191505060405180910390f35b346100005761033d600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611007565b6040518082815260200191505060405180910390f35b346100005761038d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061109a565b005b34610000576103b36004808035906020019091908035906020019091905050611881565b604051808215151515815260200191505060405180910390f35b34610000576103fe600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611948565b604051808215151515815260200191505060405180910390f35b34610000576104256119ec565b005b3461000057610458600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611ac0565b604051808215151515815260200191505060405180910390f35b346100005761048d6004808035906020019091905050611b64565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146104df575b8051825260208311156104df576020820191506020810190506020830392506104bb565b5050509050019250505060405180910390f35b346100005761050d6004808035906020019091905050611cb7565b6040518082815260200191505060405180910390f35b3461000057610575600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611ce3565b6040518082815260200191505060405180910390f35b34610000576105c5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050611d76565b005b3461000057610638600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919050506129a6565b604051808215151515815260200191505060405180910390f35b346100005761066d6004808035906020019091905050612a23565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576106d36004808035906020019091908035906020019091905050612b55565b6040518080602001828103825283818151815260200191508051906020019060200280838360008314610725575b80518252602083111561072557602082019150602081019050602083039250610701565b5050509050019250505060405180910390f35b600060018311806107495750600282115b1561075357610000565b600083141561079d576006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b60018314156107e7576006600201600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b5b92915050565b6000600082815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b919050565b61084333611948565b151561084e57610000565b600281111561085c57610000565b600081148061086b5750600281145b8015610904575061090160018054806020026020016040519081016040528092919081815260200182805480156108f757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116108ad575b5050505050610f67565b82115b1561090e57610000565b6001811480156109ab57506109a8600280548060200260200160405190810160405280929190818152602001828054801561099e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610954575b5050505050610f67565b82115b156109b557610000565b60008114156109d1578160096000015414156109d057610000565b5b60018114156109ed578160096001015414156109ec57610000565b5b6002811415610a0957816009600201541415610a0857610000565b5b6006600101600082815260200190815260200160002060000160009054906101000a900460ff161515610bbb5760016006600101600083815260200190815260200160002060000160006101000a81548160ff02191690831515021790555081600660010160008381526020019081526020016000206002018190555043600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060010181815481835581811511610aff57818360005260206000209182019101610afe91905b80821115610afa576000816000905550600101610ae2565b5090565b5b50505050600660010160008281526020019081526020016000206001018054806001018281815481835581811511610b6357818360005260206000209182019101610b6291905b80821115610b5e576000816000905550600101610b46565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610d7a565b600554600660010160008381526020019081526020016000206003015443031115610bee57610be981612d90565b610efc565b816006600101600083815260200190815260200160002060020154141515610c1557610000565b610cbc3360066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610cb257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610c68575b50505050506129a6565b15610cc657610000565b600660010160008281526020019081526020016000206001018054806001018281815481835581811511610d2657818360005260206000209182019101610d2591905b80821115610d21576000816000905550600101610d09565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600960020154610e2660066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610e1c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610dd2575b5050505050611ce3565b101515610efb576000811480610e3c5750600181145b15610e4c57610e4b6002612e63565b5b6000811415610e795760066001016000828152602001908152602001600020600201546009600001819055505b6002811415610e9757610e8c6000612e63565b610e966001612e63565b5b6001811415610ec45760066001016000828152602001908152602001600020600201546009600101819055505b6002811415610ef15760066001016000828152602001908152602001600020600201546009600201819055505b610efa81612d90565b5b5b5b5050565b60006002821115610f1157610000565b6000821415610f27576009600001549050610f54565b6001821415610f3d576009600101549050610f54565b6002821415610f53576009600201549050610f54565b5b919050565b600060008054905090505b90565b60006000600060009050600091505b8351821015610fca57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141515610fbc5780806001019150505b5b8180600101925050610f76565b8092505b5050919050565b60006002821115610fe557610000565b600660010160008381526020019081526020016000206002015490505b919050565b60006000600060009050600091505b835182101561108f57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141580156110735750611072848381518110156100005790602001906020020151611ac0565b5b156110815780806001019150505b5b8180600101925050611016565b8092505b5050919050565b600060006110a733611948565b15156110b257610000565b60008473ffffffffffffffffffffffffffffffffffffffff1614156110d657610000565b60018311156110e457610000565b60008314156111b45761117c600180548060200260200160405190810160405280929190818152602001828054801561117257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611128575b5050505050610f67565b9150600960000154821480611195575060096002015482145b1561119f57610000565b6111a884611948565b15156111b357610000565b5b600183141561127257600960010154611252600280548060200260200160405190810160405280929190818152602001828054801561124857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116111fe575b5050505050610f67565b141561125d57610000565b61126684611ac0565b151561127157610000565b5b6006600201600084815260200190815260200160002060000160009054906101000a900460ff16151561145e5760016006600201600085815260200190815260200160002060000160006101000a81548160ff021916908315150217905550836006600201600085815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550436006600201600085815260200190815260200160002060030181905550600060066002016000858152602001908152602001600020600101818154818355818115116113a2578183600052602060002091820191016113a191905b8082111561139d576000816000905550600101611385565b5090565b5b505050506006600201600084815260200190815260200160002060010180548060010182818154818355818115116114065781836000526020600020918201910161140591905b808211156114015760008160009055506001016113e9565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050611669565b6005546006600201600085815260200190815260200160002060030154430311156114915761148c83612f70565b61187a565b8373ffffffffffffffffffffffffffffffffffffffff166006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561150457610000565b6115ab33600660020160008681526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156115a157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611557575b50505050506129a6565b156115b557610000565b6006600201600084815260200190815260200160002060010180548060010182818154818355818115116116155781836000526020600020918201910161161491905b808211156116105760008160009055506001016115f8565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b6009600201546117156006600201600086815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561170b57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116116c1575b5050505050611ce3565b1015156118795760008314801561176a57506117696006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b5b156117b3576117b2836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b60018314801561180157506118006006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b1561184a57611849836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b600090505b600381101561186f5761186181612e63565b5b808060010191505061184f565b61187883612f70565b5b5b5b50505050565b600060028311806118925750600282115b1561189c57610000565b60008314156118d3576006600001600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b600183141561190a576006600101600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b6002831415611941576006600201600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b5b92915050565b60006000600090505b6001805490508110156119e1578273ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156119d357600191506119e6565b5b8080600101915050611951565b600091505b50919050565b600460009054906101000a900460ff1615611a0657610000565b60018054806001018281815481835581811511611a4f57818360005260206000209182019101611a4e91905b80821115611a4a576000816000905550600101611a32565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506001600460006101000a81548160ff0219169083151502179055505b565b60006000600090505b600280549050811015611b59578273ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415611b4b5760019150611b5e565b5b8080600101915050611ac9565b600091505b50919050565b60206040519081016040528060008152506001821115611b8357610000565b6000821415611c1a576001805480602002602001604051908101604052809291908181526020018280548015611c0e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611bc4575b50505050509050611cb2565b6001821415611cb1576002805480602002602001604051908101604052809291908181526020018280548015611ca557602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611c5b575b50505050509050611cb2565b5b919050565b6000600082815481101561000057906000526020600020906002020160005b506000015490505b919050565b60006000600060009050600091505b8351821015611d6b57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff1614158015611d4f5750611d4e848381518110156100005790602001906020020151611948565b5b15611d5d5780806001019150505b5b8180600101925050611cf2565b8092505b5050919050565b611d7f33611948565b158015611d925750611d9033611ac0565b155b15611d9c57610000565b600081148015611e3c5750600354611e396001805480602002602001604051908101604052809291908181526020018280548015611e2f57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611de5575b5050505050610f67565b10155b15611e4657610000565b600181148015611ee65750600354611ee36002805480602002602001604051908101604052809291908181526020018280548015611ed957602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611e8f575b5050505050610f67565b10155b15611ef057610000565b60008273ffffffffffffffffffffffffffffffffffffffff161415611f1457610000565b6002811115611f2257610000565b6000811480611f315750600181145b8015611f525750611f4182611948565b80611f515750611f5082611ac0565b5b5b15611f5c57610000565b6006600001600082815260200190815260200160002060000160009054906101000a900460ff16151561215b57611f9233611ac0565b15611f9c57610000565b60016006600001600083815260200190815260200160002060000160006101000a81548160ff021916908315150217905550816006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504360066000016000838152602001908152602001600020600301819055506000600660000160008381526020019081526020016000206001018181548183558181151161209f5781836000526020600020918201910161209e91905b8082111561209a576000816000905550600101612082565b5090565b5b505050506006600001600082815260200190815260200160002060010180548060010182818154818355818115116121035781836000526020600020918201910161210291905b808211156120fe5760008160009055506001016120e6565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050612366565b60055460066000016000838152602001908152602001600020600301544303111561218e5761218981612e63565b6129a1565b8173ffffffffffffffffffffffffffffffffffffffff166006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561220157610000565b6122a8336006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561229e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612254575b50505050506129a6565b156122b257610000565b6006600001600082815260200190815260200160002060010180548060010182818154818355818115116123125781836000526020600020918201910161231191905b8082111561230d5760008160009055506001016122f5565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b60008114806123755750600181145b1561268b576009600201546124266006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561241c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116123d2575b5050505050611ce3565b10151561268a5761246f6006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b806124b857506124b76006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b156124c257610000565b60008114156125a157600180548060010182818154818355818115116125145781836000526020600020918201910161251391905b8082111561250f5760008160009055506001016124f7565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600181141561268057600280548060010182818154818355818115116125f3578183600052602060002091820191016125f291905b808211156125ee5760008160009055506001016125d6565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b61268981612e63565b5b5b60028114156129a0576009600001546127406006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561273657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116126ec575b5050505050611ce3565b101580156127f857506009600101546127f5600660000160008481526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156127eb57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116127a1575b5050505050611007565b10155b1561299f57600060008054905011801561283d5750600143016000600160008054905003815481101561000057906000526020600020906002020160005b5060000154145b1561284757610000565b600080548060010182818154818355818115116128c0576002028160020283600052602060002091820191016128bf91905b808211156128bb57600060008201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600201612879565b5090565b5b505050916000526020600020906002020160005b6040604051908101604052806001430181526020016006600001600087815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525090919091506000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505061299e81612e63565b5b5b5b5b5050565b60006000600090505b8251811015612a17578373ffffffffffffffffffffffffffffffffffffffff1683828151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff161415612a095760019150612a1c565b5b80806001019150506129af565b600091505b5092915050565b6000600060006000805490501415612a3e5760009150612b4f565b60016000805490500390505b6000811115612ad55782600082815481101561000057906000526020600020906002020160005b5060000154111515612ac657600081815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b5b808060019003915050612a4a565b8260006000815481101561000057906000526020600020906002020160005b5060000154111515612b4a5760006000815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b600091505b50919050565b60206040519081016040528060008152506002831180612b755750600282115b15612b7f57610000565b6000831415612c2d5760066000016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612c2157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612bd7575b50505050509050612d8a565b6001831415612cdb5760066001016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612ccf57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612c85575b50505050509050612d8a565b6002831415612d895760066002016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612d7d57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612d33575b50505050509050612d8a565b5b92915050565b6000600660010160008381526020019081526020016000206002018190555060006006600101600083815260200190815260200160002060010181815481835581811511612e0a57818360005260206000209182019101612e0991905b80821115612e05576000816000905550600101612ded565b5090565b5b505050506000600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060006006600001600083815260200190815260200160002060010181815481835581811511612f1757818360005260206000209182019101612f1691905b80821115612f12576000816000905550600101612efa565b5090565b5b505050506000600660000160008381526020019081526020016000206003018190555060006006600001600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600201600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060066002016000838152602001908152602001600020600101818154818355818115116130245781836000526020600020918201910161302391905b8082111561301f576000816000905550600101613007565b5090565b5b505050506000600660020160008381526020019081526020016000206003018190555060006006600201600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b6000600083141561315157600090505b600180549050811015613150578173ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561314257600181815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061308d565b5b600183141561322357600090505b600280549050811015613222578173ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561321457600281815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061315f565b5b5b5050505600a165627a7a7230582036e4abcf6c2808d63bc7a088f625291c4621d5f8e2812de8b45d7456f787eac00029", + "storage": {"3": "30","5": "21600"} }, + "0000000000000000000000000000000000000084": { "code": + "0x60606040523615610110576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c83ebac14610115578063153417471461017b57806319971cbd146101d85780631ec28e0f146101fe57806327e357461461022f5780633a32306c146102525780634364725c146102ba5780634afb4f11146102eb5780634cc0e2bc146103535780635f302e8b1461038f5780636b102c49146103cd5780636fb81cbb146104185780637b993bf314610427578063850d9758146104725780638a5a9d07146104f2578063bec171e514610523578063bf5f1e831461058b578063e9944a81146105c7578063f769ac4814610652578063f9f51401146106af575b610000565b34610000576101396004808035906020019091908035906020019091905050610738565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b346100005761019660048080359060200190919050506107ee565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576101fc600480803590602001909190803590602001909190505061083a565b005b34610000576102196004808035906020019091905050610f01565b6040518082815260200191505060405180910390f35b346100005761023c610f59565b6040518082815260200191505060405180910390f35b34610000576102a4600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610f67565b6040518082815260200191505060405180910390f35b34610000576102d56004808035906020019091905050610fd5565b6040518082815260200191505060405180910390f35b346100005761033d600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611007565b6040518082815260200191505060405180910390f35b346100005761038d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061109a565b005b34610000576103b36004808035906020019091908035906020019091905050611881565b604051808215151515815260200191505060405180910390f35b34610000576103fe600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611948565b604051808215151515815260200191505060405180910390f35b34610000576104256119ec565b005b3461000057610458600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611ac0565b604051808215151515815260200191505060405180910390f35b346100005761048d6004808035906020019091905050611b64565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146104df575b8051825260208311156104df576020820191506020810190506020830392506104bb565b5050509050019250505060405180910390f35b346100005761050d6004808035906020019091905050611cb7565b6040518082815260200191505060405180910390f35b3461000057610575600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611ce3565b6040518082815260200191505060405180910390f35b34610000576105c5600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050611d76565b005b3461000057610638600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919050506129a6565b604051808215151515815260200191505060405180910390f35b346100005761066d6004808035906020019091905050612a23565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34610000576106d36004808035906020019091908035906020019091905050612b55565b6040518080602001828103825283818151815260200191508051906020019060200280838360008314610725575b80518252602083111561072557602082019150602081019050602083039250610701565b5050509050019250505060405180910390f35b600060018311806107495750600282115b1561075357610000565b600083141561079d576006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b60018314156107e7576006600201600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506107e8565b5b92915050565b6000600082815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505b919050565b61084333611948565b151561084e57610000565b600281111561085c57610000565b600081148061086b5750600281145b8015610904575061090160018054806020026020016040519081016040528092919081815260200182805480156108f757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116108ad575b5050505050610f67565b82115b1561090e57610000565b6001811480156109ab57506109a8600280548060200260200160405190810160405280929190818152602001828054801561099e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610954575b5050505050610f67565b82115b156109b557610000565b60008114156109d1578160096000015414156109d057610000565b5b60018114156109ed578160096001015414156109ec57610000565b5b6002811415610a0957816009600201541415610a0857610000565b5b6006600101600082815260200190815260200160002060000160009054906101000a900460ff161515610bbb5760016006600101600083815260200190815260200160002060000160006101000a81548160ff02191690831515021790555081600660010160008381526020019081526020016000206002018190555043600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060010181815481835581811511610aff57818360005260206000209182019101610afe91905b80821115610afa576000816000905550600101610ae2565b5090565b5b50505050600660010160008281526020019081526020016000206001018054806001018281815481835581811511610b6357818360005260206000209182019101610b6291905b80821115610b5e576000816000905550600101610b46565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610d7a565b600554600660010160008381526020019081526020016000206003015443031115610bee57610be981612d90565b610efc565b816006600101600083815260200190815260200160002060020154141515610c1557610000565b610cbc3360066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610cb257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610c68575b50505050506129a6565b15610cc657610000565b600660010160008281526020019081526020016000206001018054806001018281815481835581811511610d2657818360005260206000209182019101610d2591905b80821115610d21576000816000905550600101610d09565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600960020154610e2660066001016000848152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610e1c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610dd2575b5050505050611ce3565b101515610efb576000811480610e3c5750600181145b15610e4c57610e4b6002612e63565b5b6000811415610e795760066001016000828152602001908152602001600020600201546009600001819055505b6002811415610e9757610e8c6000612e63565b610e966001612e63565b5b6001811415610ec45760066001016000828152602001908152602001600020600201546009600101819055505b6002811415610ef15760066001016000828152602001908152602001600020600201546009600201819055505b610efa81612d90565b5b5b5b5050565b60006002821115610f1157610000565b6000821415610f27576009600001549050610f54565b6001821415610f3d576009600101549050610f54565b6002821415610f53576009600201549050610f54565b5b919050565b600060008054905090505b90565b60006000600060009050600091505b8351821015610fca57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141515610fbc5780806001019150505b5b8180600101925050610f76565b8092505b5050919050565b60006002821115610fe557610000565b600660010160008381526020019081526020016000206002015490505b919050565b60006000600060009050600091505b835182101561108f57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff16141580156110735750611072848381518110156100005790602001906020020151611ac0565b5b156110815780806001019150505b5b8180600101925050611016565b8092505b5050919050565b600060006110a733611948565b15156110b257610000565b60008473ffffffffffffffffffffffffffffffffffffffff1614156110d657610000565b60018311156110e457610000565b60008314156111b45761117c600180548060200260200160405190810160405280929190818152602001828054801561117257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611128575b5050505050610f67565b9150600960000154821480611195575060096002015482145b1561119f57610000565b6111a884611948565b15156111b357610000565b5b600183141561127257600960010154611252600280548060200260200160405190810160405280929190818152602001828054801561124857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116111fe575b5050505050610f67565b141561125d57610000565b61126684611ac0565b151561127157610000565b5b6006600201600084815260200190815260200160002060000160009054906101000a900460ff16151561145e5760016006600201600085815260200190815260200160002060000160006101000a81548160ff021916908315150217905550836006600201600085815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550436006600201600085815260200190815260200160002060030181905550600060066002016000858152602001908152602001600020600101818154818355818115116113a2578183600052602060002091820191016113a191905b8082111561139d576000816000905550600101611385565b5090565b5b505050506006600201600084815260200190815260200160002060010180548060010182818154818355818115116114065781836000526020600020918201910161140591905b808211156114015760008160009055506001016113e9565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050611669565b6005546006600201600085815260200190815260200160002060030154430311156114915761148c83612f70565b61187a565b8373ffffffffffffffffffffffffffffffffffffffff166006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561150457610000565b6115ab33600660020160008681526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156115a157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611557575b50505050506129a6565b156115b557610000565b6006600201600084815260200190815260200160002060010180548060010182818154818355818115116116155781836000526020600020918201910161161491905b808211156116105760008160009055506001016115f8565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b6009600201546117156006600201600086815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561170b57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116116c1575b5050505050611ce3565b1015156118795760008314801561176a57506117696006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b5b156117b3576117b2836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b60018314801561180157506118006006600201600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b1561184a57611849836006600201600086815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661307d565b5b600090505b600381101561186f5761186181612e63565b5b808060010191505061184f565b61187883612f70565b5b5b5b50505050565b600060028311806118925750600282115b1561189c57610000565b60008314156118d3576006600001600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b600183141561190a576006600101600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b6002831415611941576006600201600083815260200190815260200160002060000160009054906101000a900460ff169050611942565b5b92915050565b60006000600090505b6001805490508110156119e1578273ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156119d357600191506119e6565b5b8080600101915050611951565b600091505b50919050565b600460009054906101000a900460ff1615611a0657610000565b60018054806001018281815481835581811511611a4f57818360005260206000209182019101611a4e91905b80821115611a4a576000816000905550600101611a32565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506001600460006101000a81548160ff0219169083151502179055505b565b60006000600090505b600280549050811015611b59578273ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415611b4b5760019150611b5e565b5b8080600101915050611ac9565b600091505b50919050565b60206040519081016040528060008152506001821115611b8357610000565b6000821415611c1a576001805480602002602001604051908101604052809291908181526020018280548015611c0e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611bc4575b50505050509050611cb2565b6001821415611cb1576002805480602002602001604051908101604052809291908181526020018280548015611ca557602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611c5b575b50505050509050611cb2565b5b919050565b6000600082815481101561000057906000526020600020906002020160005b506000015490505b919050565b60006000600060009050600091505b8351821015611d6b57600084838151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff1614158015611d4f5750611d4e848381518110156100005790602001906020020151611948565b5b15611d5d5780806001019150505b5b8180600101925050611cf2565b8092505b5050919050565b611d7f33611948565b158015611d925750611d9033611ac0565b155b15611d9c57610000565b600081148015611e3c5750600354611e396001805480602002602001604051908101604052809291908181526020018280548015611e2f57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611de5575b5050505050610f67565b10155b15611e4657610000565b600181148015611ee65750600354611ee36002805480602002602001604051908101604052809291908181526020018280548015611ed957602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611e8f575b5050505050610f67565b10155b15611ef057610000565b60008273ffffffffffffffffffffffffffffffffffffffff161415611f1457610000565b6002811115611f2257610000565b6000811480611f315750600181145b8015611f525750611f4182611948565b80611f515750611f5082611ac0565b5b5b15611f5c57610000565b6006600001600082815260200190815260200160002060000160009054906101000a900460ff16151561215b57611f9233611ac0565b15611f9c57610000565b60016006600001600083815260200190815260200160002060000160006101000a81548160ff021916908315150217905550816006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504360066000016000838152602001908152602001600020600301819055506000600660000160008381526020019081526020016000206001018181548183558181151161209f5781836000526020600020918201910161209e91905b8082111561209a576000816000905550600101612082565b5090565b5b505050506006600001600082815260200190815260200160002060010180548060010182818154818355818115116121035781836000526020600020918201910161210291905b808211156120fe5760008160009055506001016120e6565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050612366565b60055460066000016000838152602001908152602001600020600301544303111561218e5761218981612e63565b6129a1565b8173ffffffffffffffffffffffffffffffffffffffff166006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561220157610000565b6122a8336006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561229e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612254575b50505050506129a6565b156122b257610000565b6006600001600082815260200190815260200160002060010180548060010182818154818355818115116123125781836000526020600020918201910161231191905b8082111561230d5760008160009055506001016122f5565b5090565b5b505050916000526020600020900160005b33909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b60008114806123755750600181145b1561268b576009600201546124266006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561241c57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116123d2575b5050505050611ce3565b10151561268a5761246f6006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611948565b806124b857506124b76006600001600083815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611ac0565b5b156124c257610000565b60008114156125a157600180548060010182818154818355818115116125145781836000526020600020918201910161251391905b8082111561250f5760008160009055506001016124f7565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b600181141561268057600280548060010182818154818355818115116125f3578183600052602060002091820191016125f291905b808211156125ee5760008160009055506001016125d6565b5090565b5b505050916000526020600020900160005b6006600001600085815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b61268981612e63565b5b5b60028114156129a0576009600001546127406006600001600084815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561273657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116126ec575b5050505050611ce3565b101580156127f857506009600101546127f5600660000160008481526020019081526020016000206001018054806020026020016040519081016040528092919081815260200182805480156127eb57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116127a1575b5050505050611007565b10155b1561299f57600060008054905011801561283d5750600143016000600160008054905003815481101561000057906000526020600020906002020160005b5060000154145b1561284757610000565b600080548060010182818154818355818115116128c0576002028160020283600052602060002091820191016128bf91905b808211156128bb57600060008201600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600201612879565b5090565b5b505050916000526020600020906002020160005b6040604051908101604052806001430181526020016006600001600087815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525090919091506000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505061299e81612e63565b5b5b5b5b5050565b60006000600090505b8251811015612a17578373ffffffffffffffffffffffffffffffffffffffff1683828151811015610000579060200190602002015173ffffffffffffffffffffffffffffffffffffffff161415612a095760019150612a1c565b5b80806001019150506129af565b600091505b5092915050565b6000600060006000805490501415612a3e5760009150612b4f565b60016000805490500390505b6000811115612ad55782600082815481101561000057906000526020600020906002020160005b5060000154111515612ac657600081815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b5b808060019003915050612a4a565b8260006000815481101561000057906000526020600020906002020160005b5060000154111515612b4a5760006000815481101561000057906000526020600020906002020160005b5060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169150612b4f565b600091505b50919050565b60206040519081016040528060008152506002831180612b755750600282115b15612b7f57610000565b6000831415612c2d5760066000016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612c2157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612bd7575b50505050509050612d8a565b6001831415612cdb5760066001016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612ccf57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612c85575b50505050509050612d8a565b6002831415612d895760066002016000838152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015612d7d57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311612d33575b50505050509050612d8a565b5b92915050565b6000600660010160008381526020019081526020016000206002018190555060006006600101600083815260200190815260200160002060010181815481835581811511612e0a57818360005260206000209182019101612e0991905b80821115612e05576000816000905550600101612ded565b5090565b5b505050506000600660010160008381526020019081526020016000206003018190555060006006600101600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600001600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060006006600001600083815260200190815260200160002060010181815481835581811511612f1757818360005260206000209182019101612f1691905b80821115612f12576000816000905550600101612efa565b5090565b5b505050506000600660000160008381526020019081526020016000206003018190555060006006600001600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b60006006600201600083815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060066002016000838152602001908152602001600020600101818154818355818115116130245781836000526020600020918201910161302391905b8082111561301f576000816000905550600101613007565b5090565b5b505050506000600660020160008381526020019081526020016000206003018190555060006006600201600083815260200190815260200160002060000160006101000a81548160ff0219169083151502179055505b50565b6000600083141561315157600090505b600180549050811015613150578173ffffffffffffffffffffffffffffffffffffffff16600182815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561314257600181815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061308d565b5b600183141561322357600090505b600280549050811015613222578173ffffffffffffffffffffffffffffffffffffffff16600282815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561321457600281815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b5b808060010191505061315f565b5b5b5050505600a165627a7a7230582036e4abcf6c2808d63bc7a088f625291c4621d5f8e2812de8b45d7456f787eac00029", + "storage": {"3": "30","5": "21600"} } + } +} +)E"; diff --git a/src/eth_client/libethcore/ABI.h b/src/eth_client/libethcore/ABI.h new file mode 100644 index 0000000000..5b7d160d07 --- /dev/null +++ b/src/eth_client/libethcore/ABI.h @@ -0,0 +1,100 @@ +/* + 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 . +*/ +/** @file ABI.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ + +inline string32 toString32(std::string const& _s) +{ + string32 ret; + for (unsigned i = 0; i < 32; ++i) + ret[i] = i < _s.size() ? _s[i] : 0; + return ret; +} + +template struct ABISerialiser {}; +template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } }; +template <> struct ABISerialiser { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; +template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return bytes(12, 0) + h160(_t).asBytes(); } }; +template <> struct ABISerialiser { static bytes serialise(string32 const& _t) { bytes ret; bytesConstRef((byte const*)_t.data(), 32).populate(bytesRef(&ret)); return ret; } }; +template <> struct ABISerialiser +{ + static bytes serialise(std::string const& _t) + { + bytes ret = h256(u256(32)).asBytes() + h256(u256(_t.size())).asBytes(); + ret.resize(ret.size() + (_t.size() + 31) / 32 * 32); + bytesConstRef(&_t).populate(bytesRef(&ret).cropped(64)); + return ret; + } +}; + +inline bytes abiInAux() { return {}; } +template bytes abiInAux(T const& _t, U const& ... _u) +{ + return ABISerialiser::serialise(_t) + abiInAux(_u ...); +} + +template bytes abiIn(std::string _id, T const& ... _t) +{ + return sha3(_id).ref().cropped(0, 4).toBytes() + abiInAux(_t ...); +} + +template struct ABIDeserialiser {}; +template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(bytesRef((byte*)ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser +{ + static std::string deserialise(bytesConstRef& io_t) + { + unsigned o = (uint16_t)u256(h256(io_t.cropped(0, 32))); + unsigned s = (uint16_t)u256(h256(io_t.cropped(o, 32))); + std::string ret; + ret.resize(s); + io_t.cropped(o + 32, s).populate(bytesRef((byte*)ret.data(), s)); + io_t = io_t.cropped(32); + return ret; + } +}; + +template T abiOut(bytes const& _data) +{ + bytesConstRef o(&_data); + return ABIDeserialiser::deserialise(o); +} + +template T abiOut(bytesConstRef& _data) +{ + return ABIDeserialiser::deserialise(_data); +} + +} +} diff --git a/src/eth_client/libethcore/BlockHeader.cpp b/src/eth_client/libethcore/BlockHeader.cpp new file mode 100644 index 0000000000..ecd9987f7e --- /dev/null +++ b/src/eth_client/libethcore/BlockHeader.cpp @@ -0,0 +1,253 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include +#include +#include +#include +#include +#include +#include +#include "Exceptions.h" +#include "BlockHeader.h" +using namespace std; +using namespace dev; +using namespace dev::eth; + +BlockHeader::BlockHeader() +{ +} + +BlockHeader::BlockHeader(bytesConstRef _block, BlockDataType _bdt, h256 const& _hashWith) +{ + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); + populate(header); +} + +BlockHeader::BlockHeader(BlockHeader const& _other) : + m_parentHash(_other.parentHash()), + m_sha3Uncles(_other.sha3Uncles()), + m_stateRoot(_other.stateRoot()), + m_transactionsRoot(_other.transactionsRoot()), + m_receiptsRoot(_other.receiptsRoot()), + m_logBloom(_other.logBloom()), + m_number(_other.number()), + m_gasLimit(_other.gasLimit()), + m_gasUsed(_other.gasUsed()), + m_extraData(_other.extraData()), + m_timestamp(_other.timestamp()), + m_author(_other.author()), + m_difficulty(_other.difficulty()), + m_seal(_other.seal()), + m_hash(_other.hashRawRead()), + m_hashWithout(_other.hashWithoutRawRead()) +{ + assert(*this == _other); +} + +BlockHeader& BlockHeader::operator=(BlockHeader const& _other) +{ + if (this == &_other) + return *this; + m_parentHash = _other.parentHash(); + m_sha3Uncles = _other.sha3Uncles(); + m_stateRoot = _other.stateRoot(); + m_transactionsRoot = _other.transactionsRoot(); + m_receiptsRoot = _other.receiptsRoot(); + m_logBloom = _other.logBloom(); + m_number = _other.number(); + m_gasLimit = _other.gasLimit(); + m_gasUsed = _other.gasUsed(); + m_extraData = _other.extraData(); + m_timestamp = _other.timestamp(); + m_author = _other.author(); + m_difficulty = _other.difficulty(); + std::vector seal = _other.seal(); + { + Guard l(m_sealLock); + m_seal = std::move(seal); + } + h256 hash = _other.hashRawRead(); + h256 hashWithout = _other.hashWithoutRawRead(); + { + Guard l(m_hashLock); + m_hash = std::move(hash); + m_hashWithout = std::move(hashWithout); + } + assert(*this == _other); + return *this; +} + +void BlockHeader::clear() +{ + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_author = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = -1; + m_extraData.clear(); + m_seal.clear(); + noteDirty(); +} + +h256 BlockHeader::hash(IncludeSeal _i) const +{ + h256 dummy; + Guard l(m_hashLock); + h256& memo = _i == WithSeal ? m_hash : _i == WithoutSeal ? m_hashWithout : dummy; + if (!memo) + { + RLPStream s; + streamRLP(s, _i); + memo = sha3(s.out()); + } + return memo; +} + +void BlockHeader::streamRLPFields(RLPStream& _s) const +{ + _s << m_parentHash << m_sha3Uncles << m_author << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; +} + +void BlockHeader::streamRLP(RLPStream& _s, IncludeSeal _i) const +{ + if (_i != OnlySeal) + { + _s.appendList(BlockHeader::BasicFields + (_i == WithoutSeal ? 0 : m_seal.size())); + BlockHeader::streamRLPFields(_s); + } + if (_i != WithoutSeal) + for (unsigned i = 0; i < m_seal.size(); ++i) + _s.appendRaw(m_seal[i]); +} + +h256 BlockHeader::headerHashFromBlock(bytesConstRef _block) +{ + return sha3(RLP(_block)[0].data()); +} + +RLP BlockHeader::extractHeader(bytesConstRef _block) +{ + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("Block must be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("Block header must be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("Block transactions must be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("Block uncles must be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} + +void BlockHeader::populate(RLP const& _header) +{ + int field = 0; + try + { + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_author = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toPositiveInt64(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toPositiveInt64(); + m_extraData = _header[field = 12].toBytes(); + m_seal.clear(); + for (unsigned i = 13; i < _header.itemCount(); ++i) + m_seal.push_back(_header[i].data().toBytes()); + } + catch (Exception const& _e) + { + _e << errinfo_name("invalid block header format") << BadFieldError(field, toHex(_header[field].data().toBytes())); + throw; + } +} + +void BlockHeader::populateFromParent(BlockHeader const& _parent) +{ + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_parentHash = _parent.m_hash; + m_gasLimit = _parent.m_gasLimit; + m_difficulty = _parent.m_difficulty; + m_gasUsed = 0; +} + +void BlockHeader::verify(Strictness _s, BlockHeader const& _parent, bytesConstRef _block) const +{ + if (m_number > ~(unsigned)0) + BOOST_THROW_EXCEPTION(InvalidNumber()); + + if (_s != CheckNothingNew && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); + + if (_parent) + { + if (m_parentHash && _parent.hash() != m_parentHash) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + + if (m_timestamp <= _parent.m_timestamp) + BOOST_THROW_EXCEPTION(InvalidTimestamp()); + + if (m_number != _parent.m_number + 1) + BOOST_THROW_EXCEPTION(InvalidNumber()); + } + + if (_block) + { + RLP root(_block); + + auto txList = root[1]; + auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); + + LOG(m_logger) << "Expected trie root: " << toString(expectedRoot); + if (m_transactionsRoot != expectedRoot) + { + StateCacheDB tm; + GenericTrieDB transactionsTrie(&tm); + transactionsTrie.init(); + + vector txs; + + for (unsigned i = 0; i < txList.itemCount(); ++i) + { + RLPStream k; + k << i; + + transactionsTrie.insert(&k.out(), txList[i].data()); + + txs.push_back(txList[i].data()); + cdebug << toHex(k.out()) << toHex(txList[i].data()); + } + cdebug << "trieRootOver" << expectedRoot; + cdebug << "orderedTrieRoot" << orderedTrieRoot(txs); + cdebug << "TrieDB" << transactionsTrie.root(); + cdebug << "Contents:"; + for (auto const& t: txs) + cdebug << toHex(t); + + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); + } + LOG(m_logger) << "Expected uncle hash: " << toString(sha3(root[2].data())); + if (m_sha3Uncles != sha3(root[2].data())) + BOOST_THROW_EXCEPTION(InvalidUnclesHash() << Hash256RequirementError(sha3(root[2].data()), m_sha3Uncles)); + } +} diff --git a/src/eth_client/libethcore/BlockHeader.h b/src/eth_client/libethcore/BlockHeader.h new file mode 100644 index 0000000000..bd31e68153 --- /dev/null +++ b/src/eth_client/libethcore/BlockHeader.h @@ -0,0 +1,210 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include "ChainOperationParams.h" +#include "Common.h" +#include "Exceptions.h" +#include +#include +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ + +enum IncludeSeal +{ + WithoutSeal = 0, + WithSeal = 1, + OnlySeal = 2 +}; + +enum Strictness +{ + CheckEverything, + QuickNonce, + IgnoreSeal, + CheckNothingNew +}; + +// TODO: for implementing soon. +/*enum Check +{ + CheckBasic, + CheckExtended, + CheckBlock, + CheckParent, + CheckSeal, + CheckSealQuickly, + CheckAll = CheckBasic | CheckExtended | CheckBlock | CheckParent | CheckSeal, +}; +using Checks = FlagSet;*/ + +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); +DEV_SIMPLE_EXCEPTION(GenesisBlockCannotBeCalculated); + +/** @brief Encapsulation of a block header. + * Class to contain all of a block header's data. It is able to parse a block header and populate + * from some given RLP block serialisation with the static fromHeader(), through the method + * populate(). This will not conduct any verification above basic formating. In this case extra + * verification can be performed through verify(). + * + * The object may also be populated from an entire block through the explicit + * constructor BlockHeader(bytesConstRef) and manually with the populate() method. These will + * conduct verification of the header against the other information in the block. + * + * The object may be populated with a template given a parent BlockHeader object with the + * populateFromParent() method. The genesis block info may be retrieved with genesis() and the + * corresponding RLP block created with createGenesisBlock(). + * + * To determine the header hash without the nonce (for sealing), the method hash(WithoutNonce) is + * provided. + * + * The default constructor creates an empty object, which can be tested against with the boolean + * conversion operator. + */ +class BlockHeader +{ + friend class BlockChain; +public: + static const unsigned BasicFields = 13; + + BlockHeader(); + explicit BlockHeader(bytesConstRef _data, BlockDataType _bdt = BlockData, h256 const& _hashWith = h256()); + explicit BlockHeader(bytes const& _data, BlockDataType _bdt = BlockData, h256 const& _hashWith = h256()): BlockHeader(&_data, _bdt, _hashWith) {} + BlockHeader(BlockHeader const& _other); + BlockHeader& operator=(BlockHeader const& _other); + + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); + + explicit operator bool() const { return m_timestamp >= 0; } + + bool operator==(BlockHeader const& _cmp) const + { + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_author == _cmp.author() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); + } + bool operator!=(BlockHeader const& _cmp) const { return !operator==(_cmp); } + + void clear(); + void noteDirty() const { Guard l(m_hashLock); m_hashWithout = m_hash = h256(); } + void populateFromParent(BlockHeader const& parent); + + // TODO: pull out into abstract class Verifier. + void verify(Strictness _s = CheckEverything, BlockHeader const& _parent = BlockHeader(), bytesConstRef _block = bytesConstRef()) const; + void verify(Strictness _s, bytesConstRef _block) const { verify(_s, BlockHeader(), _block); } + + h256 hash(IncludeSeal _i = WithSeal) const; + void streamRLP(RLPStream& _s, IncludeSeal _i = WithSeal) const; + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(int64_t _v) { m_timestamp = _v; noteDirty(); } + void setAuthor(Address const& _v) { m_author = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setNumber(int64_t _v) { m_number = _v; noteDirty(); } + void setGasLimit(u256 const& _v) { m_gasLimit = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } + template void setSeal(unsigned _offset, T const& _value) { Guard l(m_sealLock); if (m_seal.size() <= _offset) m_seal.resize(_offset + 1); m_seal[_offset] = rlp(_value); noteDirty(); } + template void setSeal(T const& _value) { setSeal(0, _value); } + + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + bool hasUncles() const { return m_sha3Uncles != EmptyListSHA3; } + int64_t timestamp() const { return m_timestamp; } + Address const& author() const { return m_author; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + u256 const& gasUsed() const { return m_gasUsed; } + int64_t number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + bytes const& extraData() const { return m_extraData; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& difficulty() const { return m_difficulty; } + template T seal(unsigned _offset = 0) const { T ret; Guard l(m_sealLock); if (_offset < m_seal.size()) ret = RLP(m_seal[_offset]).convert(RLP::VeryStrict); return ret; } + +private: + void populate(RLP const& _header); + void streamRLPFields(RLPStream& _s) const; + std::vector seal() const + { + Guard l(m_sealLock); + return m_seal; + } + h256 hashRawRead() const + { + Guard l(m_hashLock); + return m_hash; + } + h256 hashWithoutRawRead() const + { + Guard l(m_hashLock); + return m_hashWithout; + } + + h256 m_parentHash; + h256 m_sha3Uncles; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + int64_t m_number = 0; + u256 m_gasLimit; + u256 m_gasUsed; + bytes m_extraData; + int64_t m_timestamp = -1; + + Address m_author; + u256 m_difficulty; + + std::vector m_seal; ///< Additional (RLP-encoded) header fields. + mutable Mutex m_sealLock; + + mutable h256 m_hash; ///< (Memoised) SHA3 hash of the block header with seal. + mutable h256 m_hashWithout; ///< (Memoised) SHA3 hash of the block header without seal. + mutable Mutex m_hashLock; ///< A lock for both m_hash and m_hashWithout. + + mutable Logger m_logger{createLogger(VerbosityDebug, "blockhdr")}; +}; + +inline std::ostream& operator<<(std::ostream& _out, BlockHeader const& _bi) +{ + _out << _bi.hash(WithoutSeal) << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.author() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); + return _out; +} + +} +} diff --git a/src/eth_client/libethcore/ChainOperationParams.cpp b/src/eth_client/libethcore/ChainOperationParams.cpp new file mode 100644 index 0000000000..bf4ab618b3 --- /dev/null +++ b/src/eth_client/libethcore/ChainOperationParams.cpp @@ -0,0 +1,84 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include "ChainOperationParams.h" +#include +#include + +using namespace std; +using namespace dev; +using namespace eth; + +PrecompiledContract::PrecompiledContract( + std::string const& _name, u256 const& _startingBlock /*= 0*/) + : m_cost(PrecompiledRegistrar::pricer(_name)), + m_execute(PrecompiledRegistrar::executor(_name)), + m_startingBlock(_startingBlock) +{} + +ChainOperationParams::ChainOperationParams(): + m_blockReward("0x4563918244F40000"), + minGasLimit(0x1388), + maxGasLimit("0x7fffffffffffffff"), + gasLimitBoundDivisor(0x0400), + networkID(0x0), + minimumDifficulty(0x020000), + difficultyBoundDivisor(0x0800), + durationLimit(0x0d) +{ +} + +EVMSchedule const& ChainOperationParams::scheduleForBlockNumber(u256 const& _blockNumber) const +{ + if (_blockNumber >= lastForkBlock) + return lastForkWithAdditionalEIPsSchedule; + else + return forkScheduleForBlockNumber(_blockNumber); +} + +EVMSchedule const& ChainOperationParams::forkScheduleForBlockNumber(u256 const& _blockNumber) const +{ + if (_blockNumber >= experimentalForkBlock) + return ExperimentalSchedule; + else if (_blockNumber >= shanghaiForkBlock) + return ShanghaiSchedule; + else if (_blockNumber >= londonForkBlock) + return LondonSchedule; + else if (_blockNumber >= berlinForkBlock) + return BerlinSchedule; + else if (_blockNumber >= muirGlacierForkBlock) + return MuirGlacierSchedule; + else if (_blockNumber >= istanbulForkBlock) + return IstanbulSchedule; + else if (_blockNumber >= constantinopleFixForkBlock) + return ConstantinopleFixSchedule; + else if (_blockNumber >= constantinopleForkBlock) + return ConstantinopleSchedule; + else if (_blockNumber >= eWASMForkBlock) + return EWASMSchedule; + else if (_blockNumber >= byzantiumForkBlock) + return ByzantiumSchedule; + else if (_blockNumber >= EIP158ForkBlock) + return EIP158Schedule; + else if (_blockNumber >= EIP150ForkBlock) + return EIP150Schedule; + else if (_blockNumber >= homesteadForkBlock) + return HomesteadSchedule; + else + return FrontierSchedule; +} + +u256 ChainOperationParams::blockReward(EVMSchedule const& _schedule) const +{ + if (_schedule.blockRewardOverwrite) + return *_schedule.blockRewardOverwrite; + else + return m_blockReward; +} + +void ChainOperationParams::setBlockReward(u256 const& _newBlockReward) +{ + m_blockReward = _newBlockReward; +} diff --git a/src/eth_client/libethcore/ChainOperationParams.h b/src/eth_client/libethcore/ChainOperationParams.h new file mode 100644 index 0000000000..f6e0e1303d --- /dev/null +++ b/src/eth_client/libethcore/ChainOperationParams.h @@ -0,0 +1,119 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include +#include + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +struct EVMSchedule; + +class PrecompiledContract +{ +public: + PrecompiledContract(std::string const& _name, u256 const& _startingBlock = 0); + + bigint cost( + bytesConstRef _in, ChainOperationParams const& _chainParams, u256 const& _blockNumber) const + { + return m_cost(_in, _chainParams, _blockNumber); + } + std::pair execute(bytesConstRef _in) const { return m_execute(_in); } + + u256 const& startingBlock() const { return m_startingBlock; } + +private: + PrecompiledPricer m_cost; + PrecompiledExecutor m_execute; + u256 m_startingBlock = 0; +}; + +constexpr int64_t c_infiniteBlockNumber = std::numeric_limits::max(); + +struct AdditionalEIPs +{ + bool eip1380 = false; + bool eip2046 = false; +}; + +struct ChainOperationParams +{ + ChainOperationParams(); + + explicit operator bool() const { return accountStartNonce != Invalid256; } + + /// The chain sealer name: e.g. Ethash, NoProof, BasicAuthority + std::string sealEngineName = "NoProof"; + + // Example of how to check EIP activation from outside of EVM: + // bool isEIP2046Enabled(u256 const& _blockNumber) const + // { + // return _blockNumber >= lastForkBlock && lastForkAdditionalEIPs.eip2046; + // } + // After hard fork finalization this is changed to: + // bool isEIP2046Enabled(u256 const& _blockNumber) const + // { + // return _blockNumber >= berlinForkBlock; + // } + + /// General chain params. +private: + u256 m_blockReward; + +public: + // returns schedule for the fork active at the given block + // may include additional individually activated EIPs on top of the last fork block + EVMSchedule const& scheduleForBlockNumber(u256 const& _blockNumber) const; + // returns schedule according to the fork rules active at the given block + // doesn't include additional individually activated EIPs + EVMSchedule const& forkScheduleForBlockNumber(u256 const& _blockNumber) const; + u256 blockReward(EVMSchedule const& _schedule) const; + void setBlockReward(u256 const& _newBlockReward); + u256 maximumExtraDataSize = 32; + u256 accountStartNonce = 0; + bool tieBreakingGas = true; + u256 minGasLimit; + u256 maxGasLimit; + u256 gasLimitBoundDivisor; + u256 homesteadForkBlock = c_infiniteBlockNumber; + u256 EIP150ForkBlock = c_infiniteBlockNumber; + u256 EIP158ForkBlock = c_infiniteBlockNumber; + u256 byzantiumForkBlock = c_infiniteBlockNumber; + u256 eWASMForkBlock = c_infiniteBlockNumber; + u256 constantinopleForkBlock = c_infiniteBlockNumber; + u256 constantinopleFixForkBlock = c_infiniteBlockNumber; + u256 daoHardforkBlock = c_infiniteBlockNumber; + u256 experimentalForkBlock = c_infiniteBlockNumber; + u256 istanbulForkBlock = c_infiniteBlockNumber; + u256 muirGlacierForkBlock = c_infiniteBlockNumber; + u256 berlinForkBlock = c_infiniteBlockNumber; + u256 londonForkBlock = c_infiniteBlockNumber; + u256 lastForkBlock = c_infiniteBlockNumber; + u256 qip6ForkBlock = c_infiniteBlockNumber; + u256 shanghaiForkBlock = c_infiniteBlockNumber; + AdditionalEIPs lastForkAdditionalEIPs; + int chainID = 0; // Distinguishes different chains (mainnet, Ropsten, etc). + int networkID = 0; // Distinguishes different sub protocols. + + u256 minimumDifficulty; + u256 difficultyBoundDivisor; + u256 durationLimit; + bool allowFutureBlocks = false; + + /// Precompiled contracts as specified in the chain params. + std::unordered_map precompiled; + + EVMSchedule lastForkWithAdditionalEIPsSchedule; +}; + +} +} diff --git a/src/eth_client/libethcore/Common.cpp b/src/eth_client/libethcore/Common.cpp new file mode 100644 index 0000000000..e13b77bf67 --- /dev/null +++ b/src/eth_client/libethcore/Common.cpp @@ -0,0 +1,175 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include "Common.h" +#include +#include +#include +#include "Exceptions.h" +#include "BlockHeader.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +namespace dev +{ +namespace eth +{ + +const unsigned c_protocolVersion = 63; +#if ETH_FATDB +const unsigned c_databaseMinorVersion = 4; +const unsigned c_databaseBaseVersion = 9; +const unsigned c_databaseVersionModifier = 1; +#else +const unsigned c_databaseMinorVersion = 3; +const unsigned c_databaseBaseVersion = 9; +const unsigned c_databaseVersionModifier = 0; +#endif + +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); + +const Address c_blockhashContractAddress(0xf0); +const bytes c_blockhashContractCode(fromHex("0x600073fffffffffffffffffffffffffffffffffffffffe33141561005957600143035b60011561005357600035610100820683015561010081061561004057005b6101008104905061010082019150610022565b506100e0565b4360003512156100d4576000356001814303035b61010081121515610085576000610100830614610088565b60005b156100a75761010083019250610100820491506101008104905061006d565b610100811215156100bd57600060a052602060a0f35b610100820683015460c052602060c0f350506100df565b600060e052602060e0f35b5b50")); + +Address toAddress(std::string const& _s) +{ + try + { + auto b = fromHex(_s.substr(0, 2) == "0x" ? _s.substr(2) : _s, WhenError::Throw); + if (b.size() == 20) + return Address(b); + } + catch (BadHexCharacter&) {} + BOOST_THROW_EXCEPTION(InvalidAddress()); +} + +vector> const& units() +{ + static const vector> s_units = + { + {exp10<54>(), "Uether"}, + {exp10<51>(), "Vether"}, + {exp10<48>(), "Dether"}, + {exp10<45>(), "Nether"}, + {exp10<42>(), "Yether"}, + {exp10<39>(), "Zether"}, + {exp10<36>(), "Eether"}, + {exp10<33>(), "Pether"}, + {exp10<30>(), "Tether"}, + {exp10<27>(), "Gether"}, + {exp10<24>(), "Mether"}, + {exp10<21>(), "grand"}, + {exp10<18>(), "ether"}, + {exp10<15>(), "finney"}, + {exp10<12>(), "szabo"}, + {exp10<9>(), "Gwei"}, + {exp10<6>(), "Mwei"}, + {exp10<3>(), "Kwei"}, + {exp10<0>(), "wei"} + }; + + return s_units; +} + +std::string formatBalance(bigint const& _b) +{ + ostringstream ret; + u256 b; + if (_b < 0) + { + ret << "-"; + b = (u256)-_b; + } + else + b = (u256)_b; + + if (b > units()[0].first * 1000) + { + ret << (b / units()[0].first) << " " << units()[0].second; + return ret.str(); + } + ret << setprecision(5); + for (auto const& i: units()) + if (i.first != 1 && b >= i.first) + { + ret << (double(b / (i.first / 1000)) / 1000.0) << " " << i.second; + return ret.str(); + } + ret << b << " wei"; + return ret.str(); +} + +static void badBlockInfo(BlockHeader const& _bi, string const& _err) +{ + string const c_line = string(80, ' '); + string const c_border = string(2, ' '); + string const c_space = c_border + string(76, ' ') + c_border; + stringstream ss; + ss << c_line << "\n"; + ss << c_space << "\n"; + ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << "\n"; + ss << c_space << "\n"; + string bin = toString(_bi.number()); + ss << c_border + (" Bad Block #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << "\n"; + ss << c_space << "\n"; + ss << c_line; + cwarn << "\n" + ss.str(); +} + +void badBlock(bytesConstRef _block, string const& _err) +{ + BlockHeader bi; + DEV_IGNORE_EXCEPTIONS(bi = BlockHeader(_block)); + badBlockInfo(bi, _err); +} + +string TransactionSkeleton::userReadable(bool _toProxy, function(TransactionSkeleton const&)> const& _getNatSpec, function const& _formatAddress) const +{ + if (creation) + { + // show notice concerning the creation code. TODO: this needs entering into natspec. + return string("ÐApp is attempting to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(value) + ", with additional network fees of up to " + formatBalance(gas * gasPrice) + ".\n\nMaximum total cost is " + formatBalance(value + gas * gasPrice) + "."; + } + + bool isContract; + std::string natSpec; + tie(isContract, natSpec) = _getNatSpec(*this); + if (!isContract) + { + // recipient has no code - nothing special about this transaction, show basic value transfer info + return "ÐApp is attempting to send " + formatBalance(value) + " to a recipient " + _formatAddress(to) + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + ", with additional network fees of up to " + formatBalance(gas * gasPrice) + ".\n\nMaximum total cost is " + formatBalance(value + gas * gasPrice) + "."; + } + + if (natSpec.empty()) + return "ÐApp is attempting to call into an unknown contract at address " + + _formatAddress(to) + ".\n\n" + + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + + "Call involves sending " + + formatBalance(value) + " to the recipient, with additional network fees of up to " + + formatBalance(gas * gasPrice) + + "However, this also does other stuff which we don't understand, and does so in your name.\n\n" + + "WARNING: This is probably going to cost you at least " + + formatBalance(value + gas * gasPrice) + + ", however this doesn't include any side-effects, which could be of far greater importance.\n\n" + + "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"; + + return "ÐApp attempting to conduct contract interaction with " + + _formatAddress(to) + + ": " + natSpec + ".\n\n" + + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + + (value > 0 ? + "In addition, ÐApp is attempting to send " + + formatBalance(value) + " to said recipient, with additional network fees of up to " + + formatBalance(gas * gasPrice) + " = " + + formatBalance(value + gas * gasPrice) + "." + : + "Additional network fees are at most" + + formatBalance(gas * gasPrice) + "."); +} + +} +} diff --git a/src/eth_client/libethcore/Common.h b/src/eth_client/libethcore/Common.h new file mode 100644 index 0000000000..8aa614dbbb --- /dev/null +++ b/src/eth_client/libethcore/Common.h @@ -0,0 +1,249 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace dev +{ + +class RLP; +class RLPStream; + +namespace eth +{ + +/// Current protocol version. +extern const unsigned c_protocolVersion; + +/// Current minor database version (for the extras database). +extern const unsigned c_databaseMinorVersion; + +/// Current database version. +extern const unsigned c_databaseVersion; + +/// Address of the special contract for block hash storage defined in EIP96 +extern const Address c_blockhashContractAddress; +/// Code of the special contract for block hash storage defined in EIP96 +extern const bytes c_blockhashContractCode; + +/// User-friendly string representation of the amount _b in wei. +std::string formatBalance(bigint const& _b); + +DEV_SIMPLE_EXCEPTION(InvalidAddress); + +/// Convert the given string into an address. +Address toAddress(std::string const& _s); + +/// Get information concerning the currency denominations. +std::vector> const& units(); + +/// The log bloom's size (2048-bit). +using LogBloom = h2048; + +/// Many log blooms. +using LogBlooms = std::vector; + +// The various denominations; here for ease of use where needed within code. +static const u256 ether = exp10<18>(); +static const u256 finney = exp10<15>(); +static const u256 szabo = exp10<12>(); +static const u256 shannon = exp10<9>(); +static const u256 wei = exp10<0>(); + +using Nonce = h64; + +using BlockNumber = unsigned; + +static const BlockNumber LatestBlock = (BlockNumber)-2; +static const BlockNumber PendingBlock = (BlockNumber)-1; +static const h256 LatestBlockHash = h256(2); +static const h256 EarliestBlockHash = h256(1); +static const h256 PendingBlockHash = h256(0); + +static const u256 DefaultBlockGasLimit = 4712388; + +enum class RelativeBlock: BlockNumber +{ + Latest = LatestBlock, + Pending = PendingBlock +}; + +enum class BlockPolarity +{ + Unknown, + Dead, + Live +}; + +class Transaction; + +struct ImportRoute +{ + h256s deadBlocks; + h256s liveBlocks; + std::vector goodTransactions; +}; + +enum class ImportResult +{ + Success = 0, + UnknownParent, + FutureTimeKnown, + FutureTimeUnknown, + AlreadyInChain, + AlreadyKnown, + Malformed, + OverbidGasPrice, + BadChain, + ZeroSignature +}; + +struct ImportRequirements +{ + using value = unsigned; + enum + { + ValidSeal = 1, ///< Validate seal + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header. + UncleParent = 128, ///< Check uncle parent block header. + PostGenesis = 256, ///< Require block to be non-genesis. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals. + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures. + OutOfOrderChecks = ValidSeal | CheckUncles | CheckTransactions, ///< Do all checks that can be done independently of prior blocks having been imported. + InOrderChecks = Parent | UncleParent, ///< Do all checks that cannot be done independently of prior blocks having been imported. + Everything = ValidSeal | CheckUncles | CheckTransactions | Parent | UncleParent, + None = 0 + }; +}; + +/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight. +template class Signal +{ +public: + using Callback = std::function; + + class HandlerAux + { + friend class Signal; + + public: + ~HandlerAux() { if (m_s) m_s->m_fire.erase(m_i); } + void reset() { m_s = nullptr; } + void fire(Args const&... _args) { m_h(_args...); } + + private: + HandlerAux(unsigned _i, Signal* _s, Callback const& _h): m_i(_i), m_s(_s), m_h(_h) {} + + unsigned m_i = 0; + Signal* m_s = nullptr; + Callback m_h; + }; + + ~Signal() + { + for (auto const& h : m_fire) + if (auto l = h.second.lock()) + l->reset(); + } + + std::shared_ptr add(Callback const& _h) + { + auto n = m_fire.empty() ? 0 : (m_fire.rbegin()->first + 1); + auto h = std::shared_ptr(new HandlerAux(n, this, _h)); + m_fire[n] = h; + return h; + } + + void operator()(Args const&... _args) + { + for (auto const& f: valuesOf(m_fire)) + if (auto h = f.lock()) + h->fire(_args...); + } + +private: + std::map> m_fire; +}; + +template using Handler = std::shared_ptr::HandlerAux>; + +struct TransactionSkeleton +{ + bool creation = false; + Address from; + Address to; + u256 value; + bytes data; + u256 nonce = Invalid256; + u256 gas = Invalid256; + u256 gasPrice = Invalid256; + + std::string userReadable(bool _toProxy, std::function(TransactionSkeleton const&)> const& _getNatSpec, std::function const& _formatAddress) const; +}; + + +void badBlock(bytesConstRef _header, std::string const& _err); +inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } + +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct WorkingProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + u256 rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + +/// Import transaction policy +enum class IfDropped +{ + Ignore, ///< Don't import transaction that was previously dropped. + Retry ///< Import transaction even if it was dropped before. +}; + +/// Errors returned from main +enum AlethErrors +{ + Success = 0, + UnrecognizedPeerset, + ArgumentProcessingFailure, + UnknownArgument, + UnknownMiningOption, + ConfigFileEmptyOrNotFound, + ConfigFileInvalid, + UnknownNetworkType, + BadNetworkIdOption, + BadConfigOption, + BadExtraDataOption, + BadAskOption, + BadBidOption, + BadFormatOption, + BadUpnpOption, + BadAddressOption, + BadHexValueInAddressOption, + BadBlockNumberHashOption, + KeyManagerInitializationFailure, + SnapshotImportFailure, + NetworkStartFailure, + BadRlp, + RlpDataNotAList, + UnsupportedJsonType, + InvalidJson +}; +} +} diff --git a/src/eth_client/libethcore/EVMSchedule.cpp b/src/eth_client/libethcore/EVMSchedule.cpp new file mode 100644 index 0000000000..23cf8d22ec --- /dev/null +++ b/src/eth_client/libethcore/EVMSchedule.cpp @@ -0,0 +1,21 @@ +/// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "EVMSchedule.h" +#include + +namespace dev +{ +namespace eth +{ +EVMSchedule::EVMSchedule(EVMSchedule const& _schedule, AdditionalEIPs const& _eips) + : EVMSchedule(_schedule) +{ + if (_eips.eip1380) + callSelfGas = 40; + if (_eips.eip2046) + precompileStaticCallGas = 40; +} +} // namespace eth +} // namespace dev diff --git a/src/eth_client/libethcore/EVMSchedule.h b/src/eth_client/libethcore/EVMSchedule.h new file mode 100644 index 0000000000..02ff1f7f0a --- /dev/null +++ b/src/eth_client/libethcore/EVMSchedule.h @@ -0,0 +1,231 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ +struct AdditionalEIPs; + +struct EVMSchedule +{ + EVMSchedule(): tierStepGas(std::array{{0, 2, 3, 5, 8, 10, 20, 0}}) {} + EVMSchedule(bool _efcd, bool _hdc, unsigned const& _txCreateGas): exceptionalFailedCodeDeposit(_efcd), haveDelegateCall(_hdc), tierStepGas(std::array{{0, 2, 3, 5, 8, 10, 20, 0}}), txCreateGas(_txCreateGas) {} + // construct schedule with additional EIPs on top + EVMSchedule(EVMSchedule const& _schedule, AdditionalEIPs const& _eips); + unsigned accountVersion = 0; + bool exceptionalFailedCodeDeposit = true; + bool haveDelegateCall = true; + bool eip150Mode = false; + bool eip158Mode = false; + bool eip1283Mode = false; + bool eip2200Mode = false; + bool eip2929Mode = false; + bool eip1559Mode = false; + bool eip6049Mode = false; + bool haveBitwiseShifting = false; + bool haveRevert = false; + bool haveReturnData = false; + bool haveStaticCall = false; + bool haveCreate2 = false; + bool haveExtcodehash = false; + bool haveChainID = false; + bool haveSelfbalance = false; + std::array tierStepGas; + unsigned expGas = 10; + unsigned expByteGas = 10; + unsigned sha3Gas = 30; + unsigned sha3WordGas = 6; + unsigned sloadGas = 50; + unsigned sstoreSetGas = 20000; + unsigned sstoreResetGas = 5000; + unsigned sstoreUnchangedGas = 200; + unsigned sstoreRefundGas = 15000; + unsigned jumpdestGas = 1; + unsigned logGas = 375; + unsigned logDataGas = 8; + unsigned logTopicGas = 375; + unsigned createGas = 32000; + unsigned callGas = 40; + unsigned precompileStaticCallGas = 700; + unsigned callSelfGas = 40; + unsigned callStipend = 2300; + unsigned callValueTransferGas = 9000; + unsigned callNewAccountGas = 25000; + unsigned selfdestructRefundGas = 24000; + unsigned memoryGas = 3; + unsigned quadCoeffDiv = 512; + unsigned createDataGas = 200; + unsigned txGas = 21000; + unsigned txCreateGas = 53000; + unsigned txDataZeroGas = 4; + unsigned txDataNonZeroGas = 68; + unsigned copyGas = 3; + + unsigned extcodesizeGas = 20; + unsigned extcodecopyGas = 20; + unsigned extcodehashGas = 400; + unsigned balanceGas = 20; + unsigned selfdestructGas = 0; + unsigned blockhashGas = 20; + unsigned maxCodeSize = unsigned(-1); + + boost::optional blockRewardOverwrite; + + bool staticCallDepthLimit() const { return !eip150Mode; } + bool emptinessIsNonexistence() const { return eip158Mode; } + bool zeroValueTransferChargesNewAccountGas() const { return !eip158Mode; } + bool sstoreNetGasMetering() const { return eip1283Mode || eip2200Mode; } + bool sstoreThrowsIfGasBelowCallStipend() const { return eip2200Mode; } + bool accessStatus() const { return eip2929Mode; } +}; + +static const EVMSchedule DefaultSchedule = EVMSchedule(); +static const EVMSchedule FrontierSchedule = EVMSchedule(false, false, 21000); +static const EVMSchedule HomesteadSchedule = EVMSchedule(true, true, 53000); + +static const EVMSchedule EIP150Schedule = [] +{ + EVMSchedule schedule = HomesteadSchedule; + schedule.eip150Mode = true; + schedule.extcodesizeGas = 700; + schedule.extcodecopyGas = 700; + schedule.balanceGas = 400; + schedule.sloadGas = 200; + schedule.callGas = 700; + schedule.callSelfGas = 700; + schedule.selfdestructGas = 5000; + return schedule; +}(); + +static const EVMSchedule EIP158Schedule = [] +{ + EVMSchedule schedule = EIP150Schedule; + schedule.expByteGas = 50; + schedule.eip158Mode = true; + schedule.maxCodeSize = 0x6000; + return schedule; +}(); + +static const EVMSchedule ByzantiumSchedule = [] +{ + EVMSchedule schedule = EIP158Schedule; + schedule.haveRevert = true; + schedule.haveReturnData = true; + schedule.haveStaticCall = true; + schedule.blockRewardOverwrite = {3 * ether}; + return schedule; +}(); + +static const EVMSchedule EWASMSchedule = [] +{ + EVMSchedule schedule = ByzantiumSchedule; + schedule.maxCodeSize = std::numeric_limits::max(); + return schedule; +}(); + +static const EVMSchedule ConstantinopleSchedule = [] +{ + EVMSchedule schedule = ByzantiumSchedule; + schedule.haveCreate2 = true; + schedule.haveBitwiseShifting = true; + schedule.haveExtcodehash = true; + schedule.eip1283Mode = true; + schedule.blockRewardOverwrite = {2 * ether}; + return schedule; +}(); + +static const EVMSchedule ConstantinopleFixSchedule = [] { + EVMSchedule schedule = ConstantinopleSchedule; + schedule.eip1283Mode = false; + return schedule; +}(); + +static const EVMSchedule IstanbulSchedule = [] { + EVMSchedule schedule = ConstantinopleFixSchedule; + schedule.txDataNonZeroGas = 16; + schedule.sloadGas = 800; + schedule.balanceGas = 700; + schedule.extcodehashGas = 700; + schedule.haveChainID = true; + schedule.haveSelfbalance = true; + schedule.eip2200Mode = true; + schedule.sstoreUnchangedGas = 800; + return schedule; +}(); + +static const EVMSchedule& MuirGlacierSchedule = IstanbulSchedule; + +static const EVMSchedule BerlinSchedule = [] { + EVMSchedule schedule = MuirGlacierSchedule; + schedule.eip2929Mode = true; + + // sloadGas implements the changes in EIP-2929: WARM_STORAGE_READ_COST + schedule.sloadGas = 100; + // sstoreResetGas implements the changes in EIP-2929: 5000 - COLD_SLOAD_COST + schedule.sstoreResetGas = 2900; + + // Warm storage read cost + schedule.extcodesizeGas = 100; + schedule.extcodecopyGas = 100; + schedule.extcodehashGas = 100; + schedule.balanceGas = 100; + schedule.callGas = 100; + schedule.callSelfGas = 100; + schedule.precompileStaticCallGas = 100; + return schedule; +}(); + +static const EVMSchedule LondonSchedule = [] { + EVMSchedule schedule = BerlinSchedule; + // London revision + schedule.eip1559Mode = true; + + // selfdestructRefundGas implements the changes in EIP-2539 and EIP-3529 (no refunds) + schedule.selfdestructRefundGas = 0; + // sstoreRefundGas implements the changes in EIP-3529: + // SSTORE_CLEARS_SCHEDULE is defined as SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST + // Which becomes: 5000 - 2100 + 1900 = 4800 + schedule.sstoreRefundGas = 4800; + return schedule; +}(); + +static const EVMSchedule ShanghaiSchedule = [] { + EVMSchedule schedule = LondonSchedule; + // Shanghai revision + schedule.eip6049Mode = true; + + return schedule; +}(); + +static const EVMSchedule ExperimentalSchedule = [] { + EVMSchedule schedule = ShanghaiSchedule; + schedule.accountVersion = 1; + schedule.blockhashGas = 800; + return schedule; +}(); + +inline EVMSchedule const& latestScheduleForAccountVersion(u256 const& _version) +{ + if (_version == 0) + return ShanghaiSchedule; + else if (_version == ExperimentalSchedule.accountVersion) + return ExperimentalSchedule; + else + { + // This should not happen, as all existing accounts + // are created either with version 0 or with one of fork's versions + assert(false); + return DefaultSchedule; + } +} +} +} diff --git a/src/eth_client/libethcore/Exceptions.h b/src/eth_client/libethcore/Exceptions.h new file mode 100644 index 0000000000..6311f8ebbe --- /dev/null +++ b/src/eth_client/libethcore/Exceptions.h @@ -0,0 +1,101 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +// information to add to exceptions +using errinfo_name = boost::error_info; +using errinfo_field = boost::error_info; +using errinfo_data = boost::error_info; +using errinfo_nonce = boost::error_info; +using errinfo_difficulty = boost::error_info; +using errinfo_target = boost::error_info; +using errinfo_seedHash = boost::error_info; +using errinfo_mixHash = boost::error_info; +using errinfo_ethashResult = boost::error_info>; +using errinfo_importResult = boost::error_info; +using BadFieldError = boost::tuple; + +DEV_SIMPLE_EXCEPTION(OutOfGasBase); +DEV_SIMPLE_EXCEPTION(OutOfGasIntrinsic); +DEV_SIMPLE_EXCEPTION(NotEnoughAvailableSpace); +DEV_SIMPLE_EXCEPTION(NotEnoughCash); +DEV_SIMPLE_EXCEPTION(GasPriceTooLow); +DEV_SIMPLE_EXCEPTION(BlockGasLimitReached); +DEV_SIMPLE_EXCEPTION(FeeTooSmall); +DEV_SIMPLE_EXCEPTION(TooMuchGasUsed); +DEV_SIMPLE_EXCEPTION(ExtraDataTooBig); +DEV_SIMPLE_EXCEPTION(ExtraDataIncorrect); +DEV_SIMPLE_EXCEPTION(TransactionIsUnsigned); +DEV_SIMPLE_EXCEPTION(InvalidSignature); +DEV_SIMPLE_EXCEPTION(InvalidTransactionFormat); +DEV_SIMPLE_EXCEPTION(InvalidBlockFormat); +DEV_SIMPLE_EXCEPTION(InvalidUnclesHash); +DEV_SIMPLE_EXCEPTION(TooManyUncles); +DEV_SIMPLE_EXCEPTION(UncleTooOld); +DEV_SIMPLE_EXCEPTION(UncleIsBrother); +DEV_SIMPLE_EXCEPTION(UncleInChain); +DEV_SIMPLE_EXCEPTION(UncleParentNotInChain); +DEV_SIMPLE_EXCEPTION(InvalidStateRoot); +DEV_SIMPLE_EXCEPTION(InvalidGasUsed); +DEV_SIMPLE_EXCEPTION(InvalidTransactionsRoot); +DEV_SIMPLE_EXCEPTION(InvalidDifficulty); +DEV_SIMPLE_EXCEPTION(InvalidGasLimit); +DEV_SIMPLE_EXCEPTION(InvalidReceiptsStateRoot); +DEV_SIMPLE_EXCEPTION(InvalidTimestamp); +DEV_SIMPLE_EXCEPTION(InvalidLogBloom); +DEV_SIMPLE_EXCEPTION(InvalidNonce); +DEV_SIMPLE_EXCEPTION(InvalidBlockHeaderItemCount); +DEV_SIMPLE_EXCEPTION(InvalidBlockNonce); +DEV_SIMPLE_EXCEPTION(InvalidParentHash); +DEV_SIMPLE_EXCEPTION(InvalidUncleParentHash); +DEV_SIMPLE_EXCEPTION(InvalidNumber); +DEV_SIMPLE_EXCEPTION(InvalidZeroSignatureTransaction); +DEV_SIMPLE_EXCEPTION(InvalidTransactionReceiptFormat); +DEV_SIMPLE_EXCEPTION(TransactionReceiptVersionError); +DEV_SIMPLE_EXCEPTION(PendingTransactionAlreadyExists); +DEV_SIMPLE_EXCEPTION(TransactionAlreadyInChain); +DEV_SIMPLE_EXCEPTION(BlockNotFound); +DEV_SIMPLE_EXCEPTION(UnknownParent); +DEV_SIMPLE_EXCEPTION(DisjointChain); +DEV_SIMPLE_EXCEPTION(AddressAlreadyUsed); +DEV_SIMPLE_EXCEPTION(ZeroSignatureTransaction); +DEV_SIMPLE_EXCEPTION(UnknownTransactionValidationError); +DEV_SIMPLE_EXCEPTION(UnknownError); + +DEV_SIMPLE_EXCEPTION(InvalidDatabaseKind); +DEV_SIMPLE_EXCEPTION(DatabaseAlreadyOpen); +DEV_SIMPLE_EXCEPTION(DatabaseCorruption); +DEV_SIMPLE_EXCEPTION(DatabaseExists); +DEV_SIMPLE_EXCEPTION(DatabaseRebuildFailed); + +DEV_SIMPLE_EXCEPTION(DAGCreationFailure); +DEV_SIMPLE_EXCEPTION(DAGComputeFailure); + +DEV_SIMPLE_EXCEPTION(UnsupportedSnapshotManifestVersion); +DEV_SIMPLE_EXCEPTION(InvalidSnapshotManifest); +DEV_SIMPLE_EXCEPTION(StateTrieReconstructionFailed); +DEV_SIMPLE_EXCEPTION(InvalidStateChunkData); +DEV_SIMPLE_EXCEPTION(InvalidBlockChunkData); +DEV_SIMPLE_EXCEPTION(AccountAlreadyImported); +DEV_SIMPLE_EXCEPTION(InvalidWarpStatusPacket); +DEV_SIMPLE_EXCEPTION(FailedToDownloadManifest); +DEV_SIMPLE_EXCEPTION(FailedToDownloadDaoForkBlockHeader); + +DEV_SIMPLE_EXCEPTION(AccountLocked); +DEV_SIMPLE_EXCEPTION(TransactionRefused); +DEV_SIMPLE_EXCEPTION(UnknownAccount); + +DEV_SIMPLE_EXCEPTION(PeerDisconnected); +} +} diff --git a/src/eth_client/libethcore/LogEntry.cpp b/src/eth_client/libethcore/LogEntry.cpp new file mode 100644 index 0000000000..0e99334d5e --- /dev/null +++ b/src/eth_client/libethcore/LogEntry.cpp @@ -0,0 +1,37 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "LogEntry.h" + +#include +#include + +namespace dev +{ +namespace eth +{ + +LogEntry::LogEntry(RLP const& _r) +{ + assert(_r.itemCount() == 3); + address = (Address)_r[0]; + topics = _r[1].toVector(); + data = _r[2].toBytes(); +} + +void LogEntry::streamRLP(RLPStream& _s) const +{ + _s.appendList(3) << address << topics << data; +} + +LogBloom LogEntry::bloom() const +{ + LogBloom ret; + ret.shiftBloom<3>(sha3(address.ref())); + for (auto t: topics) + ret.shiftBloom<3>(sha3(t.ref())); + return ret; +} + +} +} diff --git a/src/eth_client/libethcore/LogEntry.h b/src/eth_client/libethcore/LogEntry.h new file mode 100644 index 0000000000..9ce9c061d0 --- /dev/null +++ b/src/eth_client/libethcore/LogEntry.h @@ -0,0 +1,91 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2017-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#pragma once + +#include "Common.h" + +#include +#include + +namespace dev +{ + +class RLP; +class RLPStream; + +namespace eth +{ + +struct LogEntry +{ + LogEntry() = default; + explicit LogEntry(RLP const& _r); + LogEntry(Address const& _address, h256s _topics, bytes _data): + address(_address), topics(std::move(_topics)), data(std::move(_data)) + {} + + void streamRLP(RLPStream& _s) const; + + LogBloom bloom() const; + + Address address; + h256s topics; + bytes data; +}; + +using LogEntries = std::vector; + +struct LocalisedLogEntry: public LogEntry +{ + LocalisedLogEntry() = default; + explicit LocalisedLogEntry(LogEntry const& _le): LogEntry(_le) {} + + LocalisedLogEntry(LogEntry const& _le, h256 _special): + LogEntry(_le), + isSpecial(true), + special(_special) + {} + + LocalisedLogEntry( + LogEntry const& _le, + h256 const& _blockHash, + BlockNumber _blockNumber, + h256 const& _transactionHash, + unsigned _transactionIndex, + unsigned _logIndex, + BlockPolarity _polarity = BlockPolarity::Unknown + ): + LogEntry(_le), + blockHash(_blockHash), + blockNumber(_blockNumber), + transactionHash(_transactionHash), + transactionIndex(_transactionIndex), + logIndex(_logIndex), + polarity(_polarity), + mined(true) + {} + + h256 blockHash; + BlockNumber blockNumber = 0; + h256 transactionHash; + unsigned transactionIndex = 0; + unsigned logIndex = 0; + BlockPolarity polarity = BlockPolarity::Unknown; + bool mined = false; + bool isSpecial = false; + h256 special; +}; + +using LocalisedLogEntries = std::vector; + +inline LogBloom bloom(LogEntries const& _logs) +{ + LogBloom ret; + for (auto const& l: _logs) + ret |= l.bloom(); + return ret; +} + +} +} diff --git a/src/eth_client/libethcore/Precompiled.cpp b/src/eth_client/libethcore/Precompiled.cpp new file mode 100644 index 0000000000..dcc2c19bd2 --- /dev/null +++ b/src/eth_client/libethcore/Precompiled.cpp @@ -0,0 +1,323 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include "Precompiled.h" +#include "ChainOperationParams.h" +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace dev::eth; + +PrecompiledRegistrar* PrecompiledRegistrar::s_this = nullptr; + +PrecompiledExecutor const& PrecompiledRegistrar::executor(std::string const& _name) +{ + if (!get()->m_execs.count(_name)) + BOOST_THROW_EXCEPTION(ExecutorNotFound()); + return get()->m_execs[_name]; +} + +PrecompiledPricer const& PrecompiledRegistrar::pricer(std::string const& _name) +{ + if (!get()->m_pricers.count(_name)) + BOOST_THROW_EXCEPTION(PricerNotFound()); + return get()->m_pricers[_name]; +} + +namespace +{ +bigint linearPricer(unsigned _base, unsigned _word, bytesConstRef _in) +{ + bigint const s = _in.size(); + bigint const b = _base; + bigint const w = _word; + return b + (s + 31) / 32 * w; +} + +ETH_REGISTER_PRECOMPILED_PRICER(ecrecover) +(bytesConstRef /*_in*/, ChainOperationParams const& /*_chainParams*/, u256 const& /*_blockNumber*/) +{ + return 3000; +} + +ETH_REGISTER_PRECOMPILED_PRICER(btc_ecrecover) +(bytesConstRef /*_in*/, ChainOperationParams const& /*_chainParams*/, u256 const& /*_blockNumber*/) +{ + return 3000; +} + +ETH_REGISTER_PRECOMPILED(btc_ecrecover)(bytesConstRef _in) +{ + struct + { + h256 hash; + h256 v; + h256 r; + h256 s; + } in; + + memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); + + h256 ret; + try + { + bool recovered = false; + u256 v = (u256)in.v; + recovered = qtumutils::btc_ecrecover(in.hash, v, in.r, in.s, ret); + if(recovered) + { + return {true, ret.asBytes()}; + } + } + catch (...) {} + + return {true, {}}; +} + +ETH_REGISTER_PRECOMPILED(ecrecover)(bytesConstRef _in) +{ + struct + { + h256 hash; + h256 v; + h256 r; + h256 s; + } in; + + memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); + + h256 ret; + u256 v = (u256)in.v; + if (v >= 27 && v <= 28) + { + SignatureStruct sig(in.r, in.s, (dev::byte)((int)v - 27)); + if (sig.isValid()) + { + try + { + if (Public rec = recover(sig, in.hash)) + { + ret = dev::sha3(rec); + memset(ret.data(), 0, 12); + return {true, ret.asBytes()}; + } + } + catch (...) {} + } + } + return {true, {}}; +} + +ETH_REGISTER_PRECOMPILED_PRICER(sha256) +(bytesConstRef _in, ChainOperationParams const& /*_chainParams*/, u256 const& /*_blockNumber*/) +{ + return linearPricer(60, 12, _in); +} + +ETH_REGISTER_PRECOMPILED(sha256)(bytesConstRef _in) +{ + return {true, dev::sha256(_in).asBytes()}; +} + +ETH_REGISTER_PRECOMPILED_PRICER(ripemd160) +(bytesConstRef _in, ChainOperationParams const& /*_chainParams*/, u256 const& /*_blockNumber*/) +{ + return linearPricer(600, 120, _in); +} + +ETH_REGISTER_PRECOMPILED(ripemd160)(bytesConstRef _in) +{ + return {true, h256(dev::ripemd160(_in), h256::AlignRight).asBytes()}; +} + +ETH_REGISTER_PRECOMPILED_PRICER(identity) +(bytesConstRef _in, ChainOperationParams const& /*_chainParams*/, u256 const& /*_blockNumber*/) +{ + return linearPricer(15, 3, _in); +} + +ETH_REGISTER_PRECOMPILED(identity)(bytesConstRef _in) +{ + return {true, _in.toBytes()}; +} + +// Parse _count bytes of _in starting with _begin offset as big endian int. +// If there's not enough bytes in _in, consider it infinitely right-padded with zeroes. +bigint parseBigEndianRightPadded(bytesConstRef _in, bigint const& _begin, bigint const& _count) +{ + if (_begin > _in.count()) + return 0; + assert(_count <= numeric_limits::max() / 8); // Otherwise, the return value would not fit in the memory. + + size_t const begin{_begin}; + size_t const count{_count}; + + // crop _in, not going beyond its size + bytesConstRef cropped = _in.cropped(begin, min(count, _in.count() - begin)); + + bigint ret = fromBigEndian(cropped); + // shift as if we had right-padding zeroes + assert(count - cropped.count() <= numeric_limits::max() / 8); + ret <<= 8 * (count - cropped.count()); + + return ret; +} + +ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in) +{ + bigint const baseLength(parseBigEndianRightPadded(_in, 0, 32)); + bigint const expLength(parseBigEndianRightPadded(_in, 32, 32)); + bigint const modLength(parseBigEndianRightPadded(_in, 64, 32)); + assert(modLength <= numeric_limits::max() / 8); // Otherwise gas should be too expensive. + assert(baseLength <= numeric_limits::max() / 8); // Otherwise, gas should be too expensive. + if (modLength == 0 && baseLength == 0) + return {true, bytes{}}; // This is a special case where expLength can be very big. + assert(expLength <= numeric_limits::max() / 8); + + bigint const base(parseBigEndianRightPadded(_in, 96, baseLength)); + bigint const exp(parseBigEndianRightPadded(_in, 96 + baseLength, expLength)); + bigint const mod(parseBigEndianRightPadded(_in, 96 + baseLength + expLength, modLength)); + + bigint const result = mod != 0 ? boost::multiprecision::powm(base, exp, mod) : bigint{0}; + + size_t const retLength(modLength); + bytes ret(retLength); + toBigEndian(result, ret); + + return {true, ret}; +} + +namespace +{ + bigint expLengthAdjust(bigint const& _expOffset, bigint const& _expLength, bytesConstRef _in) + { + if (_expLength <= 32) + { + bigint const exp(parseBigEndianRightPadded(_in, _expOffset, _expLength)); + return exp ? msb(exp) : 0; + } + else + { + bigint const expFirstWord(parseBigEndianRightPadded(_in, _expOffset, 32)); + size_t const highestBit(expFirstWord ? msb(expFirstWord) : 0); + return 8 * (_expLength - 32) + highestBit; + } + } + + bigint multComplexity(bigint const& _x) + { + if (_x <= 64) + return _x * _x; + if (_x <= 1024) + return (_x * _x) / 4 + 96 * _x - 3072; + else + return (_x * _x) / 16 + 480 * _x - 199680; + } +} + +ETH_REGISTER_PRECOMPILED_PRICER(modexp)(bytesConstRef _in, ChainOperationParams const& _chainParams, u256 const& _blockNumber) +{ + bigint const baseLength(parseBigEndianRightPadded(_in, 0, 32)); + bigint const expLength(parseBigEndianRightPadded(_in, 32, 32)); + bigint const modLength(parseBigEndianRightPadded(_in, 64, 32)); + + bigint const maxLength(max(modLength, baseLength)); + bigint const adjustedExpLength(expLengthAdjust(baseLength + 96, expLength, _in)); + + bigint gas = maxLength; + if(_blockNumber < _chainParams.berlinForkBlock) + { + gas = multComplexity(maxLength) * max(adjustedExpLength, 1) / 20; + } + else + { + gas += 7; + gas /= 8; + gas *= gas; + gas = gas * max(adjustedExpLength, 1) / 3; + gas = max(200, gas); + } + + return gas; +} + +ETH_REGISTER_PRECOMPILED(alt_bn128_G1_add)(bytesConstRef _in) +{ + return dev::crypto::alt_bn128_G1_add(_in); +} + +ETH_REGISTER_PRECOMPILED_PRICER(alt_bn128_G1_add) +(bytesConstRef /*_in*/, ChainOperationParams const& _chainParams, u256 const& _blockNumber) +{ + return _blockNumber < _chainParams.istanbulForkBlock ? 500 : 150; +} + +ETH_REGISTER_PRECOMPILED(alt_bn128_G1_mul)(bytesConstRef _in) +{ + return dev::crypto::alt_bn128_G1_mul(_in); +} + +ETH_REGISTER_PRECOMPILED_PRICER(alt_bn128_G1_mul) +(bytesConstRef /*_in*/, ChainOperationParams const& _chainParams, u256 const& _blockNumber) +{ + return _blockNumber < _chainParams.istanbulForkBlock ? 40000 : 6000; +} + +ETH_REGISTER_PRECOMPILED(alt_bn128_pairing_product)(bytesConstRef _in) +{ + return dev::crypto::alt_bn128_pairing_product(_in); +} + +ETH_REGISTER_PRECOMPILED_PRICER(alt_bn128_pairing_product) +(bytesConstRef _in, ChainOperationParams const& _chainParams, u256 const& _blockNumber) +{ + auto const k = _in.size() / 192; + return _blockNumber < _chainParams.istanbulForkBlock ? 100000 + k * 80000 : 45000 + k * 34000; +} + +ETH_REGISTER_PRECOMPILED(blake2_compression)(bytesConstRef _in) +{ + static constexpr size_t roundsSize = 4; + static constexpr size_t stateVectorSize = 8 * 8; + static constexpr size_t messageBlockSize = 16 * 8; + static constexpr size_t offsetCounterSize = 8; + static constexpr size_t finalBlockIndicatorSize = 1; + static constexpr size_t totalInputSize = roundsSize + stateVectorSize + messageBlockSize + + 2 * offsetCounterSize + finalBlockIndicatorSize; + + if (_in.size() != totalInputSize) + return {false, {}}; + + auto const rounds = fromBigEndian(_in.cropped(0, roundsSize)); + auto const stateVector = _in.cropped(roundsSize, stateVectorSize); + auto const messageBlockVector = _in.cropped(roundsSize + stateVectorSize, messageBlockSize); + auto const offsetCounter0 = + _in.cropped(roundsSize + stateVectorSize + messageBlockSize, offsetCounterSize); + auto const offsetCounter1 = _in.cropped( + roundsSize + stateVectorSize + messageBlockSize + offsetCounterSize, offsetCounterSize); + uint8_t const finalBlockIndicator = + _in[roundsSize + stateVectorSize + messageBlockSize + 2 * offsetCounterSize]; + + if (finalBlockIndicator != 0 && finalBlockIndicator != 1) + return {false, {}}; + + return {true, dev::crypto::blake2FCompression(rounds, stateVector, offsetCounter0, + offsetCounter1, finalBlockIndicator, messageBlockVector)}; +} + +ETH_REGISTER_PRECOMPILED_PRICER(blake2_compression) +(bytesConstRef _in, ChainOperationParams const&, u256 const&) +{ + auto const rounds = fromBigEndian(_in.cropped(0, 4)); + return rounds; +} +} diff --git a/src/eth_client/libethcore/Precompiled.h b/src/eth_client/libethcore/Precompiled.h new file mode 100644 index 0000000000..b057683bf8 --- /dev/null +++ b/src/eth_client/libethcore/Precompiled.h @@ -0,0 +1,63 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ +struct ChainOperationParams; + +using PrecompiledExecutor = std::function(bytesConstRef _in)>; +using PrecompiledPricer = std::function; + +DEV_SIMPLE_EXCEPTION(ExecutorNotFound); +DEV_SIMPLE_EXCEPTION(PricerNotFound); + +class PrecompiledRegistrar +{ +public: + /// Get the executor object for @a _name function or @throw ExecutorNotFound if not found. + static PrecompiledExecutor const& executor(std::string const& _name); + + /// Get the price calculator object for @a _name function or @throw PricerNotFound if not found. + static PrecompiledPricer const& pricer(std::string const& _name); + + /// Register an executor. In general just use ETH_REGISTER_PRECOMPILED. + static PrecompiledExecutor registerExecutor(std::string const& _name, PrecompiledExecutor const& _exec) { return (get()->m_execs[_name] = _exec); } + /// Unregister an executor. Shouldn't generally be necessary. + static void unregisterExecutor(std::string const& _name) { get()->m_execs.erase(_name); } + + /// Register a pricer. In general just use ETH_REGISTER_PRECOMPILED_PRICER. + static PrecompiledPricer registerPricer(std::string const& _name, PrecompiledPricer const& _exec) { return (get()->m_pricers[_name] = _exec); } + /// Unregister a pricer. Shouldn't generally be necessary. + static void unregisterPricer(std::string const& _name) { get()->m_pricers.erase(_name); } + +private: + static PrecompiledRegistrar* get() { if (!s_this) s_this = new PrecompiledRegistrar; return s_this; } + + std::unordered_map m_execs; + std::unordered_map m_pricers; + static PrecompiledRegistrar* s_this; +}; + +// TODO: unregister on unload with a static object. +#define ETH_REGISTER_PRECOMPILED(Name) static std::pair __eth_registerPrecompiledFunction ## Name(bytesConstRef _in); static PrecompiledExecutor __eth_registerPrecompiledFactory ## Name = ::dev::eth::PrecompiledRegistrar::registerExecutor(#Name, &__eth_registerPrecompiledFunction ## Name); static std::pair __eth_registerPrecompiledFunction ## Name +#define ETH_REGISTER_PRECOMPILED_PRICER(Name) \ + static bigint __eth_registerPricerFunction##Name( \ + bytesConstRef _in, ChainOperationParams const& _chainParams, u256 const& _blockNumber); \ + static PrecompiledPricer __eth_registerPricerFactory##Name = \ + ::dev::eth::PrecompiledRegistrar::registerPricer( \ + #Name, &__eth_registerPricerFunction##Name); \ + static bigint __eth_registerPricerFunction##Name +} +} diff --git a/src/eth_client/libethcore/SealEngine.cpp b/src/eth_client/libethcore/SealEngine.cpp new file mode 100644 index 0000000000..760c6924c3 --- /dev/null +++ b/src/eth_client/libethcore/SealEngine.cpp @@ -0,0 +1,256 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "SealEngine.h" +#include "TransactionBase.h" + +using namespace std; +namespace dev +{ +namespace eth +{ +SealEngineRegistrar* SealEngineRegistrar::s_this = nullptr; + +void NoProof::init() +{ + ETH_REGISTER_SEAL_ENGINE(NoProof); +} + +void NoReward::init() +{ + ETH_REGISTER_SEAL_ENGINE(NoReward); +} + +void NoProof::populateFromParent(BlockHeader& _bi, BlockHeader const& _parent) const +{ + SealEngineFace::populateFromParent(_bi, _parent); + _bi.setDifficulty(calculateEthashDifficulty(chainParams(), _bi, _parent)); + _bi.setGasLimit(calculateGasLimit(chainParams(), _bi)); +} + +void NoProof::generateSeal(BlockHeader const& _bi) +{ + BlockHeader header(_bi); + header.setSeal(NonceField, h64{0}); + header.setSeal(MixHashField, h256{0}); + RLPStream ret; + header.streamRLP(ret); + if (m_onSealGenerated) + m_onSealGenerated(ret.out()); +} + +void NoProof::verify(Strictness _s, BlockHeader const& _bi, BlockHeader const& _parent, bytesConstRef _block) const +{ + SealEngineFace::verify(_s, _bi, _parent, _block); + + if (_parent) + { + // Check difficulty is correct given the two timestamps. + auto expected = calculateEthashDifficulty(chainParams(), _bi, _parent); + auto difficulty = _bi.difficulty(); + if (difficulty != expected) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)expected, (bigint)difficulty)); + } +} + +void SealEngineFace::verify(Strictness _s, BlockHeader const& _bi, BlockHeader const& _parent, bytesConstRef _block) const +{ + _bi.verify(_s, _parent, _block); + + if (_s != CheckNothingNew) + { + if (_bi.difficulty() < chainParams().minimumDifficulty) + BOOST_THROW_EXCEPTION( + InvalidDifficulty() << RequirementError( + bigint(chainParams().minimumDifficulty), bigint(_bi.difficulty()))); + + if (_bi.gasLimit() < chainParams().minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError( + bigint(chainParams().minGasLimit), bigint(_bi.gasLimit()))); + + if (_bi.gasLimit() > chainParams().maxGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError( + bigint(chainParams().maxGasLimit), bigint(_bi.gasLimit()))); + + if (_bi.number() && _bi.extraData().size() > chainParams().maximumExtraDataSize) + { + BOOST_THROW_EXCEPTION( + ExtraDataTooBig() + << RequirementError(bigint(chainParams().maximumExtraDataSize), + bigint(_bi.extraData().size())) + << errinfo_extraData(_bi.extraData())); + } + + u256 const& daoHardfork = chainParams().daoHardforkBlock; + if (daoHardfork != 0 && daoHardfork + 9 >= daoHardfork && _bi.number() >= daoHardfork && + _bi.number() <= daoHardfork + 9) + if (_bi.extraData() != fromHex("0x64616f2d686172642d666f726b")) + BOOST_THROW_EXCEPTION( + ExtraDataIncorrect() + << errinfo_comment("Received block from the wrong fork (invalid extradata).")); + } + + if (_parent) + { + auto gasLimit = _bi.gasLimit(); + auto parentGasLimit = _parent.gasLimit(); + if (gasLimit < chainParams().minGasLimit || gasLimit > chainParams().maxGasLimit || + gasLimit <= parentGasLimit - parentGasLimit / chainParams().gasLimitBoundDivisor || + gasLimit >= parentGasLimit + parentGasLimit / chainParams().gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION( + InvalidGasLimit() + << errinfo_min( + (bigint)((bigint)parentGasLimit - + (bigint)(parentGasLimit / chainParams().gasLimitBoundDivisor))) + << errinfo_got((bigint)gasLimit) + << errinfo_max((bigint)((bigint)parentGasLimit + + parentGasLimit / chainParams().gasLimitBoundDivisor))); + } +} + +void SealEngineFace::populateFromParent(BlockHeader& _bi, BlockHeader const& _parent) const +{ + _bi.populateFromParent(_parent); +} + +void SealEngineFace::verifyTransaction(ImportRequirements::value _ir, TransactionBase const& _t, + BlockHeader const& _header, u256 const& _gasUsed) const +{ + if ((_ir & ImportRequirements::TransactionSignatures) && _header.number() < chainParams().EIP158ForkBlock && _t.isReplayProtected()) + BOOST_THROW_EXCEPTION(InvalidSignature()); + + if ((_ir & ImportRequirements::TransactionSignatures) && + _header.number() < chainParams().experimentalForkBlock && _t.hasZeroSignature()) + BOOST_THROW_EXCEPTION(InvalidSignature()); + + if ((_ir & ImportRequirements::TransactionBasic) && + _header.number() >= chainParams().experimentalForkBlock && _t.hasZeroSignature() && + (_t.value() != 0 || _t.gasPrice() != 0 || _t.nonce() != 0)) + BOOST_THROW_EXCEPTION(InvalidZeroSignatureTransaction() << errinfo_got((bigint)_t.gasPrice()) << errinfo_got((bigint)_t.value()) << errinfo_got((bigint)_t.nonce())); + + if (_header.number() >= chainParams().homesteadForkBlock && (_ir & ImportRequirements::TransactionSignatures) && _t.hasSignature()) + _t.checkLowS(); + + eth::EVMSchedule const& schedule = evmSchedule(_header.number()); + + // Pre calculate the gas needed for execution + if ((_ir & ImportRequirements::TransactionBasic) && _t.baseGasRequired(schedule) > _t.gas()) + BOOST_THROW_EXCEPTION(OutOfGasIntrinsic() << RequirementError( + (bigint)(_t.baseGasRequired(schedule)), (bigint)_t.gas())); + + // Avoid transactions that would take us beyond the block gas limit. + if (_gasUsed + (bigint)_t.gas() > _header.gasLimit()) + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementErrorComment( + (bigint)(_header.gasLimit() - _gasUsed), (bigint)_t.gas(), + string("_gasUsed + (bigint)_t.gas() > _header.gasLimit()"))); +} + +SealEngineFace* SealEngineRegistrar::create(ChainOperationParams const& _params) +{ + SealEngineFace* ret = create(_params.sealEngineName); + assert(ret && "Seal engine not found."); + if (ret) + ret->setChainParams(_params); + return ret; +} + +EVMSchedule const& SealEngineBase::evmSchedule(u256 const& _blockNumber) const +{ + //////////////////////////////////////////////////////// // qtum + if (u256(0) == chainParams().EIP158ForkBlock && + u256(0) == chainParams().EIP150ForkBlock && + u256(0) == chainParams().homesteadForkBlock && + false == chainParams().allowFutureBlocks){ + return getQtumSchedule(); + } + //////////////////////////////////////////////////////// + return chainParams().scheduleForBlockNumber(_blockNumber); +} + +u256 SealEngineBase::blockReward(u256 const& _blockNumber) const +{ + EVMSchedule const& schedule{evmSchedule(_blockNumber)}; + return chainParams().blockReward(schedule); +} + +u256 calculateEthashDifficulty( + ChainOperationParams const& _chainParams, BlockHeader const& _bi, BlockHeader const& _parent) +{ + const unsigned c_expDiffPeriod = 100000; + + if (!_bi.number()) + throw GenesisBlockCannotBeCalculated(); + auto const& minimumDifficulty = _chainParams.minimumDifficulty; + auto const& difficultyBoundDivisor = _chainParams.difficultyBoundDivisor; + auto const& durationLimit = _chainParams.durationLimit; + + bigint target; // stick to a bigint for the target. Don't want to risk going negative. + if (_bi.number() < _chainParams.homesteadForkBlock) + // Frontier-era difficulty adjustment + target = _bi.timestamp() >= _parent.timestamp() + durationLimit ? + _parent.difficulty() - (_parent.difficulty() / difficultyBoundDivisor) : + (_parent.difficulty() + (_parent.difficulty() / difficultyBoundDivisor)); + else + { + bigint const timestampDiff = bigint(_bi.timestamp()) - _parent.timestamp(); + bigint const adjFactor = + _bi.number() < _chainParams.byzantiumForkBlock ? + max(1 - timestampDiff / 10, -99) : // Homestead-era difficulty adjustment + max((_parent.hasUncles() ? 2 : 1) - timestampDiff / 9, + -99); // Byzantium-era difficulty adjustment + + target = _parent.difficulty() + _parent.difficulty() / 2048 * adjFactor; + } + + bigint o = target; + unsigned exponentialIceAgeBlockNumber = unsigned(_parent.number() + 1); + + // EIP-2384 Istanbul/Berlin Difficulty Bomb Delay + if (_bi.number() >= _chainParams.muirGlacierForkBlock) + { + if (exponentialIceAgeBlockNumber >= 9000000) + exponentialIceAgeBlockNumber -= 9000000; + else + exponentialIceAgeBlockNumber = 0; + } + // EIP-1234 Constantinople Ice Age delay + else if (_bi.number() >= _chainParams.constantinopleForkBlock) + { + if (exponentialIceAgeBlockNumber >= 5000000) + exponentialIceAgeBlockNumber -= 5000000; + else + exponentialIceAgeBlockNumber = 0; + } + // EIP-649 Byzantium Ice Age delay + else if (_bi.number() >= _chainParams.byzantiumForkBlock) + { + if (exponentialIceAgeBlockNumber >= 3000000) + exponentialIceAgeBlockNumber -= 3000000; + else + exponentialIceAgeBlockNumber = 0; + } + + unsigned periodCount = exponentialIceAgeBlockNumber / c_expDiffPeriod; + if (periodCount > 1) + o += (bigint(1) << (periodCount - 2)); // latter will eventually become huge, so ensure + // it's a bigint. + + o = max(minimumDifficulty, o); + return u256(min(o, std::numeric_limits::max())); +} + +u256 calculateGasLimit( + ChainOperationParams const& _chainParams, BlockHeader const& _bi, u256 const& _gasFloorTarget) +{ + u256 gasFloorTarget = _gasFloorTarget == Invalid256 ? 3141562 : _gasFloorTarget; + u256 gasLimit = _bi.gasLimit(); + u256 boundDivisor = _chainParams.gasLimitBoundDivisor; + if (gasLimit < gasFloorTarget) + return min(gasFloorTarget, gasLimit + gasLimit / boundDivisor - 1); + else + return max(gasFloorTarget, + gasLimit - gasLimit / boundDivisor + 1 + (_bi.gasUsed() * 6 / 5) / boundDivisor); +} +} +} // namespace dev eth diff --git a/src/eth_client/libethcore/SealEngine.h b/src/eth_client/libethcore/SealEngine.h new file mode 100644 index 0000000000..2518266c70 --- /dev/null +++ b/src/eth_client/libethcore/SealEngine.h @@ -0,0 +1,167 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include +#include +#include +#include "BlockHeader.h" +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockHeader; +struct ChainOperationParams; +class Interface; +class PrecompiledFace; +class TransactionBase; +class EnvInfo; + +class SealEngineFace +{ +public: + SealEngineFace() + {} + virtual ~SealEngineFace() {} + + /// @returns Tuple of hash of the current block to be mined minus nonce, seed hash, target boundary. + virtual std::tuple getWork(BlockHeader const&) + { + return std::tuple{}; + } + virtual bool isMining() const { return false; } + virtual unsigned revision() const { return 0; } + virtual unsigned sealFields() const { return 0; } + virtual bytes sealRLP() const { return bytes(); } + + /// Don't forget to call Super::verify when subclassing & overriding. + virtual void verify(Strictness _s, BlockHeader const& _bi, BlockHeader const& _parent = BlockHeader(), bytesConstRef _block = bytesConstRef()) const; + /// Additional verification for transactions in blocks. + virtual void verifyTransaction(ImportRequirements::value _ir, TransactionBase const& _t, BlockHeader const& _header, u256 const& _startGasUsed) const; + /// Don't forget to call Super::populateFromParent when subclassing & overriding. + virtual void populateFromParent(BlockHeader& _bi, BlockHeader const& _parent) const; + + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + + virtual strings sealers() const { return { "default" }; } + virtual std::string sealer() const { return "default"; } + virtual void setSealer(std::string const&) {} + + virtual bool shouldSeal(Interface*) { return true; } + virtual void generateSeal(BlockHeader const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} + + ChainOperationParams const& chainParams() const { return m_params; } + void setChainParams(ChainOperationParams const& _params) { m_params = _params; } + SealEngineFace* withChainParams(ChainOperationParams const& _params) { setChainParams(_params); return this; } + virtual EVMSchedule const& evmSchedule(u256 const& _blockNumber) const = 0; + virtual u256 blockReward(u256 const& _blockNumber) const = 0; + + virtual bool isPrecompiled(Address const& _a, u256 const& _blockNumber) const + { + return m_params.precompiled.count(_a) != 0 && _blockNumber >= m_params.precompiled.at(_a).startingBlock(); + } + virtual bigint costOfPrecompiled( + Address const& _a, bytesConstRef _in, u256 const& _blockNumber) const + { + return m_params.precompiled.at(_a).cost(_in, m_params, _blockNumber); + } + virtual std::pair executePrecompiled(Address const& _a, bytesConstRef _in, u256 const&) const { return m_params.precompiled.at(_a).execute(_in); } + +////////////////////////////////////////////////////////////// // qtum + void setQtumSchedule(EVMSchedule _qtumSchedule) const { qtumSchedule = _qtumSchedule; } + + EVMSchedule& getQtumSchedule() const { return qtumSchedule; } + + //deleteAddresses is a set that keeps track of accounts that were inserted as part of sending to pubkeyhash addresses + //This is added to when doing a CALL to a non-existent address (if the account does not exist, it assumes you're sending to pubkeyhash) + //It is also added to when a SUICIDE is done where all coins are sent to a non-existent address + //After contract execution, these accounts will be deleted from the ETH database, and their vins marked dead, to ensure future executions behave the same + mutable std::set
deleteAddresses; +////////////////////////////////////////////////////////////// + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; + + mutable EVMSchedule qtumSchedule; // qtum + + ChainOperationParams m_params; +}; + +class SealEngineBase: public SealEngineFace +{ +public: + enum + { + MixHashField = 0, + NonceField = 1 + }; + void onSealGenerated(std::function const& _f) override { m_onSealGenerated = _f; } + EVMSchedule const& evmSchedule(u256 const& _blockNumber) const override; + u256 blockReward(u256 const& _blockNumber) const override; + +protected: + std::function m_onSealGenerated; +}; + +using SealEngineFactory = std::function; + +class SealEngineRegistrar +{ +public: + /// Creates the seal engine and uses it to "polish" the params (i.e. fill in implicit values) as necessary. Use this rather than the other two + /// unless you *know* that the params contain all information regarding the seal on the Genesis block. + static SealEngineFace* create(ChainOperationParams const& _params); + static SealEngineFace* create(std::string const& _name) { if (!get()->m_sealEngines.count(_name)) return nullptr; return get()->m_sealEngines[_name](); } + + template static SealEngineFactory registerSealEngine(std::string const& _name) { return (get()->m_sealEngines[_name] = [](){return new SealEngine;}); } + static void unregisterSealEngine(std::string const& _name) { get()->m_sealEngines.erase(_name); } + +private: + static SealEngineRegistrar* get() { if (!s_this) s_this = new SealEngineRegistrar; return s_this; } + + std::unordered_map m_sealEngines; + static SealEngineRegistrar* s_this; +}; + +#define ETH_REGISTER_SEAL_ENGINE(Name) static SealEngineFactory __eth_registerSealEngineFactory ## Name = SealEngineRegistrar::registerSealEngine(#Name) + +class NoProof: public eth::SealEngineBase +{ +public: + static std::string name() { return "NoProof"; } + static void init(); + void generateSeal(BlockHeader const& _bi) override; + void populateFromParent(BlockHeader& _bi, BlockHeader const& _parent) const override; + void verify(Strictness _s, BlockHeader const& _bi, BlockHeader const& _parent, bytesConstRef _block) const override; +}; + +u256 calculateEthashDifficulty( + ChainOperationParams const& _chainParams, BlockHeader const& _bi, BlockHeader const& _parent); + +u256 calculateGasLimit(ChainOperationParams const& _chainParams, BlockHeader const& _bi, + u256 const& _gasFloorTarget = Invalid256); + + +class NoReward : public NoProof +{ +public: + static std::string name() { return "NoReward"; } + static void init(); + u256 blockReward(u256 const&) const override { return 0; } +}; +} +} diff --git a/src/eth_client/libethcore/TransactionBase.cpp b/src/eth_client/libethcore/TransactionBase.cpp new file mode 100644 index 0000000000..733353a35a --- /dev/null +++ b/src/eth_client/libethcore/TransactionBase.cpp @@ -0,0 +1,225 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include +#include +#include +#include +#include "TransactionBase.h" +#include "EVMSchedule.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +TransactionBase::TransactionBase(TransactionSkeleton const& _ts, Secret const& _s): + m_type(_ts.creation ? ContractCreation : MessageCall), + m_nonce(_ts.nonce), + m_value(_ts.value), + m_receiveAddress(_ts.to), + m_gasPrice(_ts.gasPrice), + m_gas(_ts.gas), + m_data(_ts.data), + m_sender(_ts.from) +{ + if (_s) + sign(_s); +} + +TransactionBase::TransactionBase(bytesConstRef _rlpData, CheckTransaction _checkSig) +{ + RLP const rlp(_rlpData); + try + { + if (!rlp.isList()) + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("transaction RLP must be a list")); + + m_nonce = rlp[0].toInt(); + m_gasPrice = rlp[1].toInt(); + m_gas = rlp[2].toInt(); + if (!rlp[3].isData()) + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() + << errinfo_comment("recepient RLP must be a byte array")); + m_type = rlp[3].isEmpty() ? ContractCreation : MessageCall; + m_receiveAddress = rlp[3].isEmpty() ? Address() : rlp[3].toHash
(RLP::VeryStrict); + m_value = rlp[4].toInt(); + + if (!rlp[5].isData()) + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() + << errinfo_comment("transaction data RLP must be a byte array")); + + m_data = rlp[5].toBytes(); + + u256 const v = rlp[6].toInt(); + h256 const r = rlp[7].toInt(); + h256 const s = rlp[8].toInt(); + + if (isZeroSignature(r, s)) + { + m_chainId = static_cast(v); + m_vrs = SignatureStruct{r, s, 0}; + } + else + { + if (v > 36) + { + auto const chainId = (v - 35) / 2; + if (chainId > std::numeric_limits::max()) + BOOST_THROW_EXCEPTION(InvalidSignature()); + m_chainId = static_cast(chainId); + } + // only values 27 and 28 are allowed for non-replay protected transactions + else if (v != 27 && v != 28) + BOOST_THROW_EXCEPTION(InvalidSignature()); + + auto const recoveryID = + o_has_value(m_chainId) ? byte{v - (u256{*m_chainId} * 2 + 35)} : byte{v - 27}; + m_vrs = SignatureStruct{r, s, recoveryID}; + + if (_checkSig >= CheckTransaction::Cheap && !m_vrs->isValid()) + BOOST_THROW_EXCEPTION(InvalidSignature()); + } + + if (_checkSig == CheckTransaction::Everything) + m_sender = sender(); + + if (rlp.itemCount() > 9) + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("too many fields in the transaction RLP")); + } + catch (Exception& _e) + { + _e << errinfo_name("invalid transaction format: " + toString(rlp) + " RLP: " + toHex(rlp.data())); + throw; + } +} + +Address const& TransactionBase::safeSender() const noexcept +{ + try + { + return sender(); + } + catch (...) + { + return ZeroAddress; + } +} + +Address const& TransactionBase::sender() const +{ + if (!m_sender.is_initialized()) + { + if (hasZeroSignature()) + m_sender = MaxAddress; + else + { + if (!m_vrs) + BOOST_THROW_EXCEPTION(TransactionIsUnsigned()); + + auto p = recover(*m_vrs, sha3(WithoutSignature)); + if (!p) + BOOST_THROW_EXCEPTION(InvalidSignature()); + m_sender = right160(dev::sha3(bytesConstRef(p.data(), sizeof(p)))); + } + } + return *m_sender; +} + +SignatureStruct const& TransactionBase::signature() const +{ + if (!m_vrs) + BOOST_THROW_EXCEPTION(TransactionIsUnsigned()); + + return *m_vrs; +} + +u256 TransactionBase::rawV() const +{ + if (!m_vrs) + BOOST_THROW_EXCEPTION(TransactionIsUnsigned()); + + int const vOffset = o_has_value(m_chainId) ? *m_chainId * 2 + 35 : 27; + return m_vrs->v + vOffset; +} + + +void TransactionBase::sign(Secret const& _priv) +{ + auto sig = dev::sign(_priv, sha3(WithoutSignature)); + SignatureStruct sigStruct = *(SignatureStruct const*)&sig; + if (sigStruct.isValid()) + m_vrs = sigStruct; +} + +void TransactionBase::streamRLP(RLPStream& _s, IncludeSignature _sig, bool _forEip155hash) const +{ + if (m_type == NullTransaction) + return; + + _s.appendList((_sig || _forEip155hash ? 3 : 0) + 6); + _s << m_nonce << m_gasPrice << m_gas; + if (m_type == MessageCall) + _s << m_receiveAddress; + else + _s << ""; + _s << m_value << m_data; + + if (_sig) + { + if (!m_vrs) + BOOST_THROW_EXCEPTION(TransactionIsUnsigned()); + + if (hasZeroSignature()) + _s << *m_chainId; + else + _s << rawV(); + + _s << (u256)m_vrs->r << (u256)m_vrs->s; + } + else if (_forEip155hash) + _s << *m_chainId << 0 << 0; +} + +static const u256 c_secp256k1n("115792089237316195423570985008687907852837564279074904382605163141518161494337"); + +void TransactionBase::checkLowS() const +{ + if (!m_vrs) + BOOST_THROW_EXCEPTION(TransactionIsUnsigned()); + + if (m_vrs->s > c_secp256k1n / 2) + BOOST_THROW_EXCEPTION(InvalidSignature()); +} + +void TransactionBase::checkChainId(uint64_t _chainId) const +{ + if (o_has_value(m_chainId) && *m_chainId != _chainId) + BOOST_THROW_EXCEPTION(InvalidSignature()); +} + +int64_t TransactionBase::baseGasRequired(bool _contractCreation, bytesConstRef _data, EVMSchedule const& _es) +{ + int64_t g = _contractCreation ? _es.txCreateGas : _es.txGas; + + // Calculate the cost of input data. + // No risk of overflow by using int64 as long as txDataNonZeroGas is quite small + // (the value not in billions). + for (auto i: _data) + g += i ? _es.txDataNonZeroGas : _es.txDataZeroGas; + return g; +} + +h256 TransactionBase::sha3(IncludeSignature _sig) const +{ + if (_sig == WithSignature && m_hashWith) + return m_hashWith; + + RLPStream s; + streamRLP(s, _sig, isReplayProtected() && _sig == WithoutSignature); + + auto ret = dev::sha3(s.out()); + if (_sig == WithSignature) + m_hashWith = ret; + return ret; +} diff --git a/src/eth_client/libethcore/TransactionBase.h b/src/eth_client/libethcore/TransactionBase.h new file mode 100644 index 0000000000..5de400f032 --- /dev/null +++ b/src/eth_client/libethcore/TransactionBase.h @@ -0,0 +1,202 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include +#include +#include + +#include + +namespace dev +{ +namespace eth +{ + +struct EVMSchedule; + +/// Named-boolean type to encode whether a signature be included in the serialisation process. +enum IncludeSignature +{ + WithoutSignature = 0, ///< Do not include a signature. + WithSignature = 1, ///< Do include a signature. +}; + +enum class CheckTransaction +{ + None, + Cheap, + Everything +}; + +#define o_has_value(o) (o.get_ptr() != 0) + +/// Encodes a transaction, ready to be exported to or freshly imported from RLP. +class TransactionBase +{ +public: + /// Constructs a null transaction. + TransactionBase() {} + + /// Constructs a transaction from a transaction skeleton & optional secret. + TransactionBase(TransactionSkeleton const& _ts, Secret const& _s = Secret()); + + /// Constructs a signed message-call transaction. + TransactionBase(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce, Secret const& _secret): m_type(MessageCall), m_nonce(_nonce), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); } + + /// Constructs a signed contract-creation transaction. + TransactionBase(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce, Secret const& _secret): m_type(ContractCreation), m_nonce(_nonce), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); } + + /// Constructs an unsigned message-call transaction. + TransactionBase(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce = 0): m_type(MessageCall), m_nonce(_nonce), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} + + /// Constructs an unsigned contract-creation transaction. + TransactionBase(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = 0): m_type(ContractCreation), m_nonce(_nonce), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} + + /// Constructs a transaction from the given RLP. + explicit TransactionBase(bytesConstRef _rlp, CheckTransaction _checkSig); + + /// Constructs a transaction from the given RLP. + explicit TransactionBase(bytes const& _rlp, CheckTransaction _checkSig): TransactionBase(&_rlp, _checkSig) {} + + /// Checks equality of transactions. + bool operator==(TransactionBase const& _c) const { return m_type == _c.m_type && (m_type == ContractCreation || m_receiveAddress == _c.m_receiveAddress) && m_value == _c.m_value && m_data == _c.m_data; } + /// Checks inequality of transactions. + bool operator!=(TransactionBase const& _c) const { return !operator==(_c); } + + /// @returns sender of the transaction from the signature (and hash). + /// @throws TransactionIsUnsigned if signature was not initialized + Address const& sender() const; + /// Like sender() but will never throw. @returns a null Address if the signature is invalid. + Address const& safeSender() const noexcept; + /// Force the sender to a particular value. This will result in an invalid transaction RLP. + void forceSender(Address const& _a) { m_sender = _a; } + + /// @throws TransactionIsUnsigned if signature was not initialized + /// @throws InvalidSValue if the signature has an invalid S value. + void checkLowS() const; + + /// @throws InvalidSignature if the transaction is replay protected + /// and chain id is not equal to @a _chainId + void checkChainId(uint64_t _chainId) const; + + /// @returns true if transaction is non-null. + explicit operator bool() const { return m_type != NullTransaction; } + + /// @returns true if transaction is contract-creation. + bool isCreation() const { return m_type == ContractCreation; } + + /// Serialises this transaction to an RLPStream. + /// @throws TransactionIsUnsigned if including signature was requested but it was not initialized + void streamRLP(RLPStream& _s, IncludeSignature _sig = WithSignature, bool _forEip155hash = false) const; + + /// @returns the RLP serialisation of this transaction. + bytes rlp(IncludeSignature _sig = WithSignature) const { RLPStream s; streamRLP(s, _sig); return s.out(); } + + /// @returns the SHA3 hash of the RLP serialisation of this transaction. + h256 sha3(IncludeSignature _sig = WithSignature) const; + + /// @returns the amount of ETH to be transferred by this (message-call) transaction, in Wei. Synonym for endowment(). + u256 value() const { return m_value; } + + /// @returns the base fee and thus the implied exchange rate of ETH to GAS. + u256 gasPrice() const { return m_gasPrice; } + + /// @returns the total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + u256 gas() const { return m_gas; } + + /// @returns the receiving address of the message-call transaction (undefined for contract-creation transactions). + Address receiveAddress() const { return m_receiveAddress; } + + /// Synonym for receiveAddress(). + Address to() const { return m_receiveAddress; } + + /// Synonym for safeSender(). + Address from() const { return safeSender(); } + + /// @returns the data associated with this (message-call) transaction. Synonym for initCode(). + bytes const& data() const { return m_data; } + + /// @returns the transaction-count of the sender. + u256 nonce() const { return m_nonce; } + + /// Sets the nonce to the given value. Clears any signature. + void setNonce(u256 const& _n) { clearSignature(); m_nonce = _n; } + + /// @returns true if the transaction was signed + bool hasSignature() const { return o_has_value(m_vrs); } + + /// @returns true if the transaction was signed with zero signature + bool hasZeroSignature() const { return m_vrs && isZeroSignature(m_vrs->r, m_vrs->s); } + + /// @returns true if the transaction uses EIP155 replay protection + bool isReplayProtected() const { return o_has_value(m_chainId); } + + /// @returns the signature of the transaction (the signature has the sender encoded in it) + /// @throws TransactionIsUnsigned if signature was not initialized + SignatureStruct const& signature() const; + + /// @returns v value of the transaction (has chainID and recoveryID encoded in it) + /// @throws TransactionIsUnsigned if signature was not initialized + u256 rawV() const; + + void sign(Secret const& _priv); ///< Sign the transaction. + + /// @returns amount of gas required for the basic payment. + int64_t baseGasRequired(EVMSchedule const& _es) const { return baseGasRequired(isCreation(), &m_data, _es); } + + /// Get the fee associated for a transaction with the given data. + static int64_t baseGasRequired(bool _contractCreation, bytesConstRef _data, EVMSchedule const& _es); + +protected: + /// Type of transaction. + enum Type + { + NullTransaction, ///< Null transaction. + ContractCreation, ///< Transaction to create contracts - receiveAddress() is ignored. + MessageCall ///< Transaction to invoke a message call - receiveAddress() is used. + }; + + static bool isZeroSignature(u256 const& _r, u256 const& _s) { return !_r && !_s; } + + /// Clears the signature. + void clearSignature() { m_vrs = SignatureStruct(); } + + Type m_type = NullTransaction; ///< Is this a contract-creation transaction or a message-call transaction? + u256 m_nonce; ///< The transaction-count of the sender. + u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. + Address m_receiveAddress; ///< The receiving address of the transaction. + u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. + u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. + boost::optional m_vrs; ///< The signature of the transaction. Encodes the sender. + /// EIP155 value for calculating transaction hash + /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + boost::optional m_chainId; + + mutable h256 m_hashWith; ///< Cached hash of transaction with signature. + mutable boost::optional
m_sender; ///< Cached sender, determined from signature. +}; + +/// Nice name for vector of Transaction. +using TransactionBases = std::vector; + +/// Simple human-readable stream-shift operator. +inline std::ostream& operator<<(std::ostream& _out, TransactionBase const& _t) +{ + _out << _t.sha3().abridged() << "{"; + if (_t.receiveAddress()) + _out << _t.receiveAddress().abridged(); + else + _out << "[CREATE]"; + + _out << "/" << _t.data().size() << "$" << _t.value() << "+" << _t.gas() << "@" << _t.gasPrice(); + _out << "<-" << _t.safeSender().abridged() << " #" << _t.nonce() << "}"; + return _out; +} + +} +} diff --git a/src/eth_client/libethereum/Account.cpp b/src/eth_client/libethereum/Account.cpp new file mode 100644 index 0000000000..d33c2cb875 --- /dev/null +++ b/src/eth_client/libethereum/Account.cpp @@ -0,0 +1,154 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include "Account.h" +#include "SecureTrieDB.h" +#include "ValidationSchemes.h" +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; +using namespace dev::eth::validation; + +namespace fs = boost::filesystem; + +void Account::setCode(bytes&& _code, u256 const& _version) +{ + auto const newHash = sha3(_code); + if (newHash != m_codeHash) + { + m_codeCache = std::move(_code); + m_hasNewCode = true; + m_codeHash = newHash; + } + m_version = _version; +} + +void Account::resetCode() +{ + m_codeCache.clear(); + m_hasNewCode = false; + m_codeHash = EmptySHA3; + // Reset the version, as it was set together with code + m_version = 0; +} + +u256 Account::originalStorageValue(u256 const& _key, OverlayDB const& _db) const +{ + auto it = m_storageOriginal.find(_key); + if (it != m_storageOriginal.end()) + return it->second; + + // Not in the original values cache - go to the DB. + SecureTrieDB const memdb(const_cast(&_db), m_storageRoot); + std::string const payload = memdb.at(_key); + auto const value = payload.size() ? RLP(payload).toInt() : 0; + m_storageOriginal[_key] = value; + return value; +} + +namespace js = json_spirit; + +// TODO move AccountMaskObj to libtesteth (it is used only in test logic) +AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _defaultNonce, + AccountMaskMap* o_mask, const fs::path& _configPath) +{ + auto u256Safe = [](std::string const& s) -> u256 { + bigint ret(s); + if (ret >= bigint(1) << 256) + BOOST_THROW_EXCEPTION( + ValueTooLarge() << errinfo_comment("State value is equal or greater than 2**256")); + return (u256)ret; + }; + + std::unordered_map ret; + + js::mValue val; + json_spirit::read_string_or_throw(_json, val); + + for (auto const& account : val.get_obj()) + { + Address a(fromHex(account.first)); + auto const& accountMaskJson = account.second.get_obj(); + + bool haveBalance = (accountMaskJson.count(c_wei) || accountMaskJson.count(c_finney) || + accountMaskJson.count(c_balance)); + bool haveNonce = accountMaskJson.count(c_nonce); + bool haveCode = accountMaskJson.count(c_code) || accountMaskJson.count(c_codeFromFile); + bool haveStorage = accountMaskJson.count(c_storage); + bool shouldNotExists = accountMaskJson.count(c_shouldnotexist); + + if (haveStorage || haveCode || haveNonce || haveBalance) + { + u256 balance = 0; + if (accountMaskJson.count(c_wei)) + balance = u256Safe(accountMaskJson.at(c_wei).get_str()); + else if (accountMaskJson.count(c_finney)) + balance = u256Safe(accountMaskJson.at(c_finney).get_str()) * finney; + else if (accountMaskJson.count(c_balance)) + balance = u256Safe(accountMaskJson.at(c_balance).get_str()); + + u256 nonce = + haveNonce ? u256Safe(accountMaskJson.at(c_nonce).get_str()) : _defaultNonce; + + ret[a] = Account(nonce, balance); + auto codeIt = accountMaskJson.find(c_code); + if (codeIt != accountMaskJson.end()) + { + auto& codeObj = codeIt->second; + if (codeObj.type() == json_spirit::str_type) + { + auto& codeStr = codeObj.get_str(); + if (codeStr.find("0x") != 0 && !codeStr.empty()) + cerr << "Error importing code of account " << a + << "! Code needs to be hex bytecode prefixed by \"0x\"."; + else + ret[a].setCode(fromHex(codeStr), 0); + } + else + cerr << "Error importing code of account " << a + << "! Code field needs to be a string"; + } + + auto codePathIt = accountMaskJson.find(c_codeFromFile); + if (codePathIt != accountMaskJson.end()) + { + auto& codePathObj = codePathIt->second; + if (codePathObj.type() == json_spirit::str_type) + { + fs::path codePath{codePathObj.get_str()}; + if (codePath.is_relative()) // Append config dir if code file path is relative. + codePath = _configPath.parent_path() / codePath; + bytes code = contents(codePath); + if (code.empty()) + cerr << "Error importing code of account " << a << "! Code file " + << codePath << " empty or does not exist.\n"; + ret[a].setCode(std::move(code), 0); + } + else + cerr << "Error importing code of account " << a + << "! Code file path must be a string\n"; + } + + if (haveStorage) + for (pair const& j : accountMaskJson.at(c_storage).get_obj()) + ret[a].setStorage(u256(j.first), u256(j.second.get_str())); + } + + if (o_mask) + { + (*o_mask)[a] = + AccountMask(haveBalance, haveNonce, haveCode, haveStorage, shouldNotExists); + if (!haveStorage && !haveCode && !haveNonce && !haveBalance && + shouldNotExists) // defined only shouldNotExists field + ret[a] = Account(0, 0); + } + } + + return ret; +} diff --git a/src/eth_client/libethereum/Account.h b/src/eth_client/libethereum/Account.h new file mode 100644 index 0000000000..0ffdb76bc0 --- /dev/null +++ b/src/eth_client/libethereum/Account.h @@ -0,0 +1,276 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include +#include +#include + +#include + +namespace dev +{ +class OverlayDB; + +namespace eth +{ + +/** + * Models the state of a single Ethereum account. + * Used to cache a portion of the full Ethereum state. State keeps a mapping of Address's to Accounts. + * + * Aside from storing the nonce and balance, the account may also be "dead" (where isAlive() returns false). + * This allows State to explicitly store the notion of a deleted account in it's cache. kill() can be used + * for this. + * + * For the account's storage, the class operates a cache. baseRoot() specifies the base state of the storage + * given as the Trie root to be looked up in the state database. Alterations beyond this base are specified + * in the overlay, stored in this class and retrieved with storageOverlay(). setStorage allows the overlay + * to be altered. + * + * The constructor allows you to create an one of a number of "types" of accounts. The default constructor + * makes a dead account (this is ignored by State when writing out the Trie). Another three allow a basic + * or contract account to be specified along with an initial balance. The fina two allow either a basic or + * a contract account to be created with arbitrary values. + */ +class Account +{ +public: + /// Changedness of account to create. + enum Changedness + { + /// Account starts as though it has been changed. + Changed, + /// Account starts as though it has not been changed. + Unchanged + }; + + /// Construct a dead Account. + Account() {} + + /// Construct an alive Account, with given endowment, for either a normal (non-contract) account + /// or for a contract account in the conception phase, where the code is not yet known. + Account(u256 _nonce, u256 _balance, Changedness _c = Changed): m_isAlive(true), m_isUnchanged(_c == Unchanged), m_nonce(_nonce), m_balance(_balance) {} + + /// Explicit constructor for wierd cases of construction or a contract account. + Account(u256 const& _nonce, u256 const& _balance, h256 const& _contractRoot, + h256 const& _codeHash, u256 const& _version, Changedness _c) + : m_isAlive(true), + m_isUnchanged(_c == Unchanged), + m_nonce(_nonce), + m_balance(_balance), + m_storageRoot(_contractRoot), + m_codeHash(_codeHash), + m_version(_version) + { + assert(_contractRoot); + } + + + /// Kill this account. Useful for the SELFDESTRUCT instruction. + /// Following this call, isAlive() returns false. + void kill() + { + m_isAlive = false; + m_storageOverlay.clear(); + m_storageOriginal.clear(); + m_codeHash = EmptySHA3; + m_storageRoot = EmptyTrie; + m_balance = 0; + m_nonce = 0; + m_version = 0; + changed(); + } + + /// @returns true iff this object represents an account in the state. + /// Returns false if this object represents an account that should no longer exist in the trie + /// (an account that never existed or was selfdestructed). + bool isAlive() const { return m_isAlive; } + + /// @returns true if the account is unchanged from creation. + bool isDirty() const { return !m_isUnchanged; } + + void untouch() { m_isUnchanged = true; } + + /// @returns true if the nonce, balance and code is zero / empty. Code is considered empty + /// during creation phase. + bool isEmpty() const { return nonce() == 0 && balance() == 0 && codeHash() == EmptySHA3; } + + /// @returns the balance of this account. + u256 const& balance() const { return m_balance; } + + /// Increments the balance of this account by the given amount. + void addBalance(u256 _value) { m_balance += _value; changed(); } + + /// @returns the nonce of the account. + u256 nonce() const { return m_nonce; } + + /// Increment the nonce of the account by one. + void incNonce() { ++m_nonce; changed(); } + + /// Set nonce to a new value. This is used when reverting changes made to + /// the account. + void setNonce(u256 const& _nonce) { m_nonce = _nonce; changed(); } + + /// @returns the root of the trie (whose nodes are stored in the state db externally to this class) + /// which encodes the base-state of the account's storage (upon which the storage is overlaid). + h256 baseRoot() const { assert(m_storageRoot); return m_storageRoot; } + + /// @returns account's storage value corresponding to the @_key + /// taking into account overlayed modifications + u256 storageValue(u256 const& _key, OverlayDB const& _db) const + { + auto mit = m_storageOverlay.find(_key); + if (mit != m_storageOverlay.end()) + return mit->second; + + return originalStorageValue(_key, _db); + } + + /// @returns account's original storage value corresponding to the @_key + /// not taking into account overlayed modifications + u256 originalStorageValue(u256 const& _key, OverlayDB const& _db) const; + + /// @returns the storage overlay as a simple hash map. + std::unordered_map const& storageOverlay() const { return m_storageOverlay; } + + /// Set a key/value pair in the account's storage. This actually goes into the overlay, for committing + /// to the trie later. + void setStorage(u256 _p, u256 _v) { m_storageOverlay[_p] = _v; changed(); } + + /// Empty the storage. Used when a contract is overwritten. + void clearStorage() + { + m_storageOverlay.clear(); + m_storageOriginal.clear(); + m_storageRoot = EmptyTrie; + changed(); + } + + /// Set the storage root. Used when clearStorage() is reverted. + void setStorageRoot(h256 const& _root) + { + m_storageOverlay.clear(); + m_storageOriginal.clear(); + m_storageRoot = _root; + changed(); + } + + /// @returns the hash of the account's code. + h256 codeHash() const { return m_codeHash; } + + bool hasNewCode() const { return m_hasNewCode; } + + /// Sets the code of the account. Used by "create" messages. + void setCode(bytes&& _code, u256 const& _version); + + /// Reset the code set by previous setCode + void resetCode(); + + /// Specify to the object what the actual code is for the account. @a _code must have a SHA3 + /// equal to codeHash(). + void noteCode(bytesConstRef _code) { assert(sha3(_code) == m_codeHash); m_codeCache = _code.toBytes(); } + + /// @returns the account's code. + bytes const& code() const { return m_codeCache; } + + u256 version() const { return m_version; } + +private: + /// Note that we've altered the account. + void changed() { m_isUnchanged = false; } + + /// Is this account existant? If not, it represents a deleted account. + bool m_isAlive = false; + + /// True if we've not made any alteration to the account having been given it's properties directly. + bool m_isUnchanged = false; + + /// True if new code was deployed to the account + bool m_hasNewCode = false; + + /// Account's nonce. + u256 m_nonce; + + /// Account's balance. + u256 m_balance = 0; + + /// The base storage root. Used with the state DB to give a base to the storage. m_storageOverlay is + /// overlaid on this and takes precedence for all values set. + h256 m_storageRoot = EmptyTrie; + + /** If c_contractConceptionCodeHash then we're in the limbo where we're running the initialisation code. + * We expect a setCode() at some point later. + * If EmptySHA3, then m_code, which should be empty, is valid. + * If anything else, then m_code is valid iff it's not empty, otherwise, State::ensureCached() needs to + * be called with the correct args. + */ + h256 m_codeHash = EmptySHA3; + + /// Account's version + u256 m_version = 0; + + /// The map with is overlaid onto whatever storage is implied by the m_storageRoot in the trie. + mutable std::unordered_map m_storageOverlay; + + /// The cache of unmodifed storage items + mutable std::unordered_map m_storageOriginal; + + /// The associated code for this account. The SHA3 of this should be equal to m_codeHash unless + /// m_codeHash equals c_contractConceptionCodeHash. + bytes m_codeCache; + + /// Value for m_codeHash when this account is having its code determined. + static const h256 c_contractConceptionCodeHash; +}; + +class AccountMask +{ +public: + AccountMask(bool _all = false): + m_hasBalance(_all), + m_hasNonce(_all), + m_hasCode(_all), + m_hasStorage(_all) + {} + + AccountMask( + bool _hasBalance, + bool _hasNonce, + bool _hasCode, + bool _hasStorage, + bool _shouldNotExist = false + ): + m_hasBalance(_hasBalance), + m_hasNonce(_hasNonce), + m_hasCode(_hasCode), + m_hasStorage(_hasStorage), + m_shouldNotExist(_shouldNotExist) + {} + + bool allSet() const { return m_hasBalance && m_hasNonce && m_hasCode && m_hasStorage; } + bool hasBalance() const { return m_hasBalance; } + bool hasNonce() const { return m_hasNonce; } + bool hasCode() const { return m_hasCode; } + bool hasStorage() const { return m_hasStorage; } + bool shouldExist() const { return !m_shouldNotExist; } + +private: + bool m_hasBalance; + bool m_hasNonce; + bool m_hasCode; + bool m_hasStorage; + bool m_shouldNotExist = false; +}; + +using AccountMap = std::unordered_map; +using AccountMaskMap = std::unordered_map; + +AccountMap jsonToAccountMap(std::string const& _json, u256 const& _defaultNonce = 0, + AccountMaskMap* o_mask = nullptr, const boost::filesystem::path& _configPath = {}); +} +} diff --git a/src/eth_client/libethereum/ChainParams.cpp b/src/eth_client/libethereum/ChainParams.cpp new file mode 100644 index 0000000000..6f41e06530 --- /dev/null +++ b/src/eth_client/libethereum/ChainParams.cpp @@ -0,0 +1,287 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "ChainParams.h" +#include "Account.h" +#include "State.h" +#include "ValidationSchemes.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace eth; +using namespace eth::validation; +namespace js = json_spirit; + +namespace +{ +u256 findMaxForkBlockNumber(js::mObject const& _params) +{ + u256 maxForkBlockNumber = 0; + for (auto const& paramKeyValue : _params) + { + auto const& key = paramKeyValue.first; + if (boost::algorithm::ends_with(key, c_forkBlockSuffix)) + { + auto const& value = paramKeyValue.second; + auto const blockNumber = fromBigEndian(fromHex(value.get_str())); + if (blockNumber < c_infiniteBlockNumber && blockNumber > maxForkBlockNumber) + maxForkBlockNumber = blockNumber; + } + } + + return maxForkBlockNumber; +} +} // namespace + +ChainParams::ChainParams() +{ + for (unsigned i = 1; i <= 4; ++i) + genesisState[Address(i)] = Account(0, 1); + // Setup default precompiled contracts as equal to genesis of Frontier. + precompiled.insert(make_pair(Address(1), PrecompiledContract("ecrecover"))); + precompiled.insert(make_pair(Address(2), PrecompiledContract("sha256"))); + precompiled.insert(make_pair(Address(3), PrecompiledContract("ripemd160"))); + precompiled.insert(make_pair(Address(4), PrecompiledContract("identity"))); +} + +ChainParams::ChainParams( + string const& _json, h256 const& _stateRoot, boost::filesystem::path const& _configPath) +{ + loadConfig(_json, _stateRoot, _configPath); +} + +ChainParams::ChainParams(std::string const& _configJson, AdditionalEIPs const& _additionalEIPs) + : ChainParams(_configJson) +{ + lastForkAdditionalEIPs = _additionalEIPs; + + // create EVM schedule + EVMSchedule const& lastForkSchedule = forkScheduleForBlockNumber(lastForkBlock); + lastForkWithAdditionalEIPsSchedule = EVMSchedule{lastForkSchedule, _additionalEIPs}; +} + +void ChainParams::loadConfig( + string const& _json, h256 const& _stateRoot, boost::filesystem::path const& _configPath) +{ + js::mValue val; + + try + { + js::read_string_or_throw(_json, val); + } + catch (js::Error_position const& error) + { + std::string const comment = "json parsing error detected on line " + + std::to_string(error.line_) + " in column " + + std::to_string(error.column_) + ": " + error.reason_; + std::cerr << comment << "\n"; + BOOST_THROW_EXCEPTION(SyntaxError() << errinfo_comment(comment)); + } + + js::mObject obj = val.get_obj(); + + validateConfigJson(obj); + + // params + sealEngineName = obj[c_sealEngine].get_str(); + js::mObject params = obj[c_params].get_obj(); + + // Params that are not required and could be set to default value + if (params.count(c_accountStartNonce)) + accountStartNonce = fromBigEndian(fromHex(params[c_accountStartNonce].get_str())); + if (params.count(c_maximumExtraDataSize)) + maximumExtraDataSize = + fromBigEndian(fromHex(params[c_maximumExtraDataSize].get_str())); + + tieBreakingGas = params.count(c_tieBreakingGas) ? params[c_tieBreakingGas].get_bool() : true; + if (params.count(c_blockReward)) + setBlockReward(fromBigEndian(fromHex(params[c_blockReward].get_str()))); + + auto setOptionalU256Parameter = [¶ms](u256 &_destination, string const& _name) + { + if (params.count(_name)) + _destination = fromBigEndian(fromHex(params.at(_name).get_str())); + }; + setOptionalU256Parameter(minGasLimit, c_minGasLimit); + setOptionalU256Parameter(maxGasLimit, c_maxGasLimit); + setOptionalU256Parameter(gasLimitBoundDivisor, c_gasLimitBoundDivisor); + + setOptionalU256Parameter(homesteadForkBlock, c_homesteadForkBlock); + setOptionalU256Parameter(daoHardforkBlock, c_daoHardforkBlock); + setOptionalU256Parameter(EIP150ForkBlock, c_EIP150ForkBlock); + setOptionalU256Parameter(EIP158ForkBlock, c_EIP158ForkBlock); + setOptionalU256Parameter(byzantiumForkBlock, c_byzantiumForkBlock); + setOptionalU256Parameter(eWASMForkBlock, c_eWASMForkBlock); + setOptionalU256Parameter(constantinopleForkBlock, c_constantinopleForkBlock); + setOptionalU256Parameter(constantinopleFixForkBlock, c_constantinopleFixForkBlock); + setOptionalU256Parameter(istanbulForkBlock, c_istanbulForkBlock); + setOptionalU256Parameter(muirGlacierForkBlock, c_muirGlacierForkBlock); + setOptionalU256Parameter(berlinForkBlock, c_berlinForkBlock); + setOptionalU256Parameter(londonForkBlock, c_londonForkBlock); + setOptionalU256Parameter(experimentalForkBlock, c_experimentalForkBlock); + setOptionalU256Parameter(qip6ForkBlock, c_qip6ForkBlock); + setOptionalU256Parameter(shanghaiForkBlock, c_shanghaiForkBlock); + + lastForkBlock = findMaxForkBlockNumber(params); + lastForkWithAdditionalEIPsSchedule = forkScheduleForBlockNumber(lastForkBlock); + + setOptionalU256Parameter(minimumDifficulty, c_minimumDifficulty); + setOptionalU256Parameter(difficultyBoundDivisor, c_difficultyBoundDivisor); + setOptionalU256Parameter(durationLimit, c_durationLimit); + + if (params.count(c_chainID)) + chainID = int(fromBigEndian(fromHex(params.at(c_chainID).get_str()))); + if (params.count(c_networkID)) + networkID = int(fromBigEndian(fromHex(params.at(c_networkID).get_str()))); + allowFutureBlocks = params.count(c_allowFutureBlocks); + + // genesis + string genesisStr = js::write_string(obj[c_genesis], false); + loadGenesis(genesisStr, _stateRoot); + // genesis state + if (contains(obj, c_accounts)) + { + string genesisStateStr = js::write_string(obj[c_accounts], false); + genesisState = jsonToAccountMap(genesisStateStr, accountStartNonce, nullptr, _configPath); + } + + precompiled.insert({Address{0x1}, PrecompiledContract{"ecrecover"}}); + precompiled.insert({Address{0x2}, PrecompiledContract{"sha256"}}); + precompiled.insert({Address{0x3}, PrecompiledContract{"ripemd160"}}); + precompiled.insert({Address{0x4}, PrecompiledContract{"identity"}}); + precompiled.insert({Address{0x5}, PrecompiledContract{"modexp", byzantiumForkBlock}}); + precompiled.insert({Address{0x6}, PrecompiledContract{"alt_bn128_G1_add", byzantiumForkBlock}}); + precompiled.insert({Address{0x7}, PrecompiledContract{"alt_bn128_G1_mul", byzantiumForkBlock}}); + precompiled.insert( + {Address{0x8}, PrecompiledContract{"alt_bn128_pairing_product", byzantiumForkBlock}}); + precompiled.insert( + {Address{0x9}, PrecompiledContract{"blake2_compression", istanbulForkBlock}}); + precompiled.insert({Address{0x85}, PrecompiledContract{"btc_ecrecover", qip6ForkBlock}}); + + stateRoot = _stateRoot ? _stateRoot : calculateStateRoot(true); +} + +void ChainParams::loadGenesis(string const& _json, h256 const& _stateRoot) +{ + js::mValue val; + js::read_string(_json, val); + js::mObject genesis = val.get_obj(); + + parentHash = h256(0); // required by the YP + author = genesis.count(c_coinbase) ? h160(genesis[c_coinbase].get_str()) : + h160(genesis[c_author].get_str()); + difficulty = genesis.count(c_difficulty) ? + u256(fromBigEndian(fromHex(genesis[c_difficulty].get_str()))) : + minimumDifficulty; + gasLimit = u256(fromBigEndian(fromHex(genesis[c_gasLimit].get_str()))); + gasUsed = genesis.count(c_gasUsed) ? + u256(fromBigEndian(fromHex(genesis[c_gasUsed].get_str()))) : + 0; + timestamp = u256(fromBigEndian(fromHex(genesis[c_timestamp].get_str()))); + extraData = bytes(fromHex(genesis[c_extraData].get_str())); + + // magic code for handling ethash stuff: + if (genesis.count(c_mixHash) && genesis.count(c_nonce)) + { + h256 mixHash(genesis[c_mixHash].get_str()); + h64 nonce(genesis[c_nonce].get_str()); + sealFields = 2; + sealRLP = rlp(mixHash) + rlp(nonce); + } + stateRoot = _stateRoot ? _stateRoot : calculateStateRoot(); +} + +SealEngineFace* ChainParams::createSealEngine() +{ + SealEngineFace* ret = SealEngineRegistrar::create(sealEngineName); + assert(ret && "Seal engine not found"); + if (!ret) + return nullptr; + ret->setChainParams(*this); + if (sealRLP.empty()) + { + sealFields = ret->sealFields(); + sealRLP = ret->sealRLP(); + } + return ret; +} + +void ChainParams::populateFromGenesis(bytes const& _genesisRLP, AccountMap const& _state) +{ + BlockHeader bi(_genesisRLP, RLP(&_genesisRLP)[0].isList() ? BlockData : HeaderData); + parentHash = bi.parentHash(); + author = bi.author(); + difficulty = bi.difficulty(); + gasLimit = bi.gasLimit(); + gasUsed = bi.gasUsed(); + timestamp = bi.timestamp(); + extraData = bi.extraData(); + genesisState = _state; + RLP r(_genesisRLP); + sealFields = r[0].itemCount() - BlockHeader::BasicFields; + sealRLP.clear(); + for (unsigned i = BlockHeader::BasicFields; i < r[0].itemCount(); ++i) + sealRLP += r[0][i].data(); + + calculateStateRoot(true); + + auto b = genesisBlock(); + if (b != _genesisRLP) + { + cdebug << "Block passed:" << bi.hash() << bi.hash(WithoutSeal); + cdebug << "Genesis now:" << BlockHeader::headerHashFromBlock(b); + cdebug << RLP(b); + cdebug << RLP(_genesisRLP); + throw 0; + } +} + +h256 ChainParams::calculateStateRoot(bool _force) const +{ + StateCacheDB db; + SecureTrieDB state(&db); + state.init(); + if (!stateRoot || _force) + { + // TODO: use hash256 + //stateRoot = hash256(toBytesMap(gs)); + dev::eth::commit(genesisState, state); + stateRoot = state.root(); + } + return stateRoot; +} + +bytes ChainParams::genesisBlock() const +{ + RLPStream block(3); + + calculateStateRoot(); + + block.appendList(BlockHeader::BasicFields + sealFields) + << parentHash + << EmptyListSHA3 // sha3(uncles) + << author + << stateRoot + << EmptyTrie // transactions + << EmptyTrie // receipts + << LogBloom() + << difficulty + << 0 // number + << gasLimit + << gasUsed // gasUsed + << timestamp + << extraData; + block.appendRaw(sealRLP, sealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} diff --git a/src/eth_client/libethereum/ChainParams.h b/src/eth_client/libethereum/ChainParams.h new file mode 100644 index 0000000000..c22343b0d2 --- /dev/null +++ b/src/eth_client/libethereum/ChainParams.h @@ -0,0 +1,72 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include +#include +#include +#include "Account.h" + +namespace dev +{ +namespace eth +{ + +class SealEngineFace; + +struct ChainParams: public ChainOperationParams +{ + ChainParams(); + ChainParams(ChainParams const& /*_org*/) = default; + ChainParams(std::string const& _configJson, h256 const& _stateRoot = {}, + boost::filesystem::path const& _configPath = {}); + /// params with additional EIPs activated on top of the last fork block + ChainParams(std::string const& _configJson, AdditionalEIPs const& _additionalEIPs); + ChainParams(bytes const& _genesisRLP, AccountMap const& _state) + { + populateFromGenesis(_genesisRLP, _state); + } + ChainParams(std::string const& _json, bytes const& _genesisRLP, AccountMap const& _state) + : ChainParams(_json) + { + populateFromGenesis(_genesisRLP, _state); + } + + SealEngineFace* createSealEngine(); + + /// Genesis params. + h256 parentHash = h256(); + Address author = Address(); + u256 difficulty = 1; + u256 gasLimit = 1 << 31; + u256 gasUsed = 0; + u256 timestamp = 0; + bytes extraData; + mutable h256 stateRoot; ///< Only pre-populate if known equivalent to genesisState's root. If they're different Bad Things Will Happen. + AccountMap genesisState; + + unsigned sealFields = 0; + bytes sealRLP; + + h256 calculateStateRoot(bool _force = false) const; + + /// Genesis block info. + bytes genesisBlock() const; + +private: + /// load config + void loadConfig(std::string const& _json, h256 const& _stateRoot, + boost::filesystem::path const& _configPath); + + void populateFromGenesis(bytes const& _genesisRLP, AccountMap const& _state); + + /// load genesis + void loadGenesis(std::string const& _json, h256 const& _stateRoot); +}; + +} +} diff --git a/src/eth_client/libethereum/CodeSizeCache.h b/src/eth_client/libethereum/CodeSizeCache.h new file mode 100644 index 0000000000..2696f4c669 --- /dev/null +++ b/src/eth_client/libethereum/CodeSizeCache.h @@ -0,0 +1,63 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include +#include + +namespace dev +{ +namespace eth +{ + +/** + * @brief Simple thread-safe cache to store a mapping from code hash to code size. + * If the cache is full, a random element is removed. + */ +class CodeSizeCache +{ +public: + void store(h256 const& _hash, size_t size) + { + UniqueGuard g(x_cache); + if (m_cache.size() >= c_maxSize) + removeRandomElement(); + m_cache[_hash] = size; + } + bool contains(h256 const& _hash) const + { + UniqueGuard g(x_cache); + return m_cache.count(_hash); + } + size_t get(h256 const& _hash) const + { + UniqueGuard g(x_cache); + return m_cache.at(_hash); + } + + static CodeSizeCache& instance() { static CodeSizeCache cache; return cache; } + +private: + /// Removes a random element from the cache. + void removeRandomElement() + { + if (!m_cache.empty()) + { + auto it = m_cache.lower_bound(h256::random()); + if (it == m_cache.end()) + it = m_cache.begin(); + m_cache.erase(it); + } + } + + static const size_t c_maxSize = 50000; + mutable Mutex x_cache; + std::map m_cache; +}; + +} +} + diff --git a/src/eth_client/libethereum/DatabasePaths.cpp b/src/eth_client/libethereum/DatabasePaths.cpp new file mode 100644 index 0000000000..5f9134ce7f --- /dev/null +++ b/src/eth_client/libethereum/DatabasePaths.cpp @@ -0,0 +1,64 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "DatabasePaths.h" +#include "libdevcore/CommonIO.h" +#include "libethcore/Common.h" + +namespace dev +{ +namespace eth +{ +namespace fs = boost::filesystem; + +DatabasePaths::DatabasePaths(fs::path const& _rootPath, h256 const& _genesisHash) noexcept +{ + // Allow an empty root path and empty genesis hash since they are required by the tests + m_rootPath = _rootPath; + m_chainPath = m_rootPath / fs::path(toHex(_genesisHash.ref().cropped(0, 4))) / fs::path(toString(c_databaseVersion)); + m_statePath = m_chainPath / fs::path("state"); + m_blocksPath = m_chainPath / fs::path("blocks"); + + auto const extrasRootPath = m_chainPath; + m_extrasPath = extrasRootPath / fs::path("extras"); + m_extrasTemporaryPath = extrasRootPath / fs::path("extras.old"); + m_extrasMinorVersionPath = m_extrasPath / fs::path("minor"); +} + +fs::path const& DatabasePaths::rootPath() const noexcept +{ + return m_rootPath; +} + +fs::path const& DatabasePaths::chainPath() const noexcept +{ + return m_chainPath; +} + +fs::path const& DatabasePaths::statePath() const noexcept +{ + return m_statePath; +} + +fs::path const& DatabasePaths::blocksPath() const noexcept +{ + return m_blocksPath; +} + +fs::path const& DatabasePaths::extrasPath() const noexcept +{ + return m_extrasPath; +} + +fs::path const& DatabasePaths::extrasTemporaryPath() const noexcept +{ + return m_extrasTemporaryPath; +} + +fs::path const& DatabasePaths::extrasMinorVersionPath() const noexcept +{ + return m_extrasMinorVersionPath; +} +} // namespace eth +} // namespace dev diff --git a/src/eth_client/libethereum/DatabasePaths.h b/src/eth_client/libethereum/DatabasePaths.h new file mode 100644 index 0000000000..cbd35d5f1c --- /dev/null +++ b/src/eth_client/libethereum/DatabasePaths.h @@ -0,0 +1,36 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "libdevcore/FixedHash.h" +#include + +namespace dev +{ +namespace eth +{ +class DatabasePaths +{ +public: + DatabasePaths(boost::filesystem::path const& _rootPath, h256 const& _genesisHash) noexcept; + boost::filesystem::path const& rootPath() const noexcept; + boost::filesystem::path const& chainPath() const noexcept; + boost::filesystem::path const& blocksPath() const noexcept; + boost::filesystem::path const& statePath() const noexcept; + boost::filesystem::path const& extrasPath() const noexcept; + boost::filesystem::path const& extrasTemporaryPath() const noexcept; + boost::filesystem::path const& extrasMinorVersionPath() const noexcept; + +private: + boost::filesystem::path m_rootPath; + boost::filesystem::path m_chainPath; + boost::filesystem::path m_blocksPath; + boost::filesystem::path m_statePath; + boost::filesystem::path m_extrasPath; + boost::filesystem::path m_extrasTemporaryPath; + boost::filesystem::path m_extrasMinorVersionPath; +}; +} // namespace eth +} // namespace dev \ No newline at end of file diff --git a/src/eth_client/libethereum/Executive.cpp b/src/eth_client/libethereum/Executive.cpp new file mode 100644 index 0000000000..70bc423ee3 --- /dev/null +++ b/src/eth_client/libethereum/Executive.cpp @@ -0,0 +1,435 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "Executive.h" +#include "ExtVM.h" +#include "State.h" +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + +namespace +{ +Address const c_RipemdPrecompiledAddress{0x03}; + +std::string dumpStorage(ExtVM const& _ext) +{ + ostringstream o; + o << " STORAGE\n"; + for (auto const& i : _ext.state().storage(_ext.myAddress)) + o << showbase << hex << i.second.first << ": " << i.second.second << "\n"; + return o.str(); +}; +} // namespace + +u256 Executive::gasUsed() const +{ + return m_t.gas() - m_gas; +} + +void Executive::accrueSubState(SubState& _parentContext) +{ + if (m_ext) + _parentContext += m_ext->sub; +} + +void Executive::initialize(Transaction const& _transaction) +{ + m_t = _transaction; + m_baseGasRequired = m_t.baseGasRequired(m_sealEngine.evmSchedule(m_envInfo.number())); + try + { + m_sealEngine.verifyTransaction(ImportRequirements::Everything, m_t, m_envInfo.header(), m_envInfo.gasUsed()); + } + catch (Exception const& ex) + { + m_excepted = toTransactionException(ex); + throw; + } + + if (!m_t.hasZeroSignature()) + { + // Avoid invalid transactions. + u256 nonceReq; + try + { + nonceReq = m_s.getNonce(m_t.sender()); + } + catch (InvalidSignature const&) + { + LOG(m_execLogger) << "Invalid Signature"; + m_excepted = TransactionException::InvalidSignature; + throw; + } + if (m_t.nonce() != nonceReq) + { + LOG(m_execLogger) << "Sender: " << m_t.sender().hex() << " Invalid Nonce: Required " + << nonceReq << ", received " << m_t.nonce(); + m_excepted = TransactionException::InvalidNonce; + BOOST_THROW_EXCEPTION( + InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce())); + } + + // Avoid unaffordable transactions. + bigint gasCost = (bigint)m_t.gas() * m_t.gasPrice(); + bigint totalCost = m_t.value() + gasCost; + if (m_s.balance(m_t.sender()) < totalCost) + { + LOG(m_execLogger) << "Not enough cash: Require > " << totalCost << " = " << m_t.gas() + << " * " << m_t.gasPrice() << " + " << m_t.value() << " Got" + << m_s.balance(m_t.sender()) << " for sender: " << m_t.sender(); + m_excepted = TransactionException::NotEnoughCash; + m_excepted = TransactionException::NotEnoughCash; + BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(totalCost, (bigint)m_s.balance(m_t.sender())) << errinfo_comment(m_t.sender().hex())); + } + m_gasCost = (u256)gasCost; // Convert back to 256-bit, safe now. + } +} + +bool Executive::execute() +{ + // Entry point for a user-executed transaction. + + // Pay... + LOG(m_detailsLogger) << "Paying " << formatBalance(m_gasCost) << " from sender for gas (" + << m_t.gas() << " gas at " << formatBalance(m_t.gasPrice()) << ")"; + m_s.subBalance(m_t.sender(), m_gasCost); + + assert(m_t.gas() >= (u256)m_baseGasRequired); + if (m_t.isCreation()) + return create(m_t.sender(), m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)m_baseGasRequired, &m_t.data(), m_t.sender()); + else + return call(m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)m_baseGasRequired); +} + +bool Executive::call(Address const& _receiveAddress, Address const& _senderAddress, u256 const& _value, u256 const& _gasPrice, bytesConstRef _data, u256 const& _gas) +{ + CallParameters params{_senderAddress, _receiveAddress, _receiveAddress, _value, _value, _gas, _data, {}}; + return call(params, _gasPrice, _senderAddress); +} + +bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address const& _origin) +{ + // If external transaction. + if (m_t) + { + // FIXME: changelog contains unrevertable balance change that paid + // for the transaction. + // Increment associated nonce for sender. + if (_p.senderAddress != MaxAddress || + m_envInfo.number() < m_sealEngine.chainParams().experimentalForkBlock) // EIP86 + m_s.incNonce(_p.senderAddress); + } + + m_savepoint = m_s.savepoint(); + + if (m_sealEngine.isPrecompiled(_p.codeAddress, m_envInfo.number())) + { + // Empty RIPEMD contract needs to be deleted even in case of OOG + // because of the anomaly on the main net caused by buggy behavior by both Geth and Parity + // https://github.com/ethereum/go-ethereum/pull/3341/files#diff-2433aa143ee4772026454b8abd76b9dd + // https://github.com/ethereum/EIPs/issues/716 + // https://github.com/ethereum/aleth/pull/5664 + // We mark the account as touched here, so that is can be removed among other touched empty + // accounts (after tx finalization) + if (_p.receiveAddress == c_RipemdPrecompiledAddress) + m_s.unrevertableTouch(_p.codeAddress); + + bigint g = m_sealEngine.costOfPrecompiled(_p.codeAddress, _p.data, m_envInfo.number()); + if (_p.gas < g) + { + m_excepted = TransactionException::OutOfGasBase; + // Bail from exception. + return true; // true actually means "all finished - nothing more to be done regarding go(). + } + else + { + m_gas = (u256)(_p.gas - g); + bytes output; + bool success; + tie(success, output) = m_sealEngine.executePrecompiled(_p.codeAddress, _p.data, m_envInfo.number()); + size_t outputSize = output.size(); + m_output = owning_bytes_ref{std::move(output), 0, outputSize}; + if (!success) + { + m_gas = 0; + m_excepted = TransactionException::OutOfGas; + return true; // true means no need to run go(). + } + } + } + else + { + m_gas = _p.gas; + if (m_s.addressHasCode(_p.codeAddress)) + { + bytes const& c = m_s.code(_p.codeAddress); + h256 codeHash = m_s.codeHash(_p.codeAddress); + // Contract will be executed with the version stored in account + auto const version = m_s.version(_p.codeAddress); + m_ext = make_shared(m_s, m_envInfo, m_sealEngine, _p.receiveAddress, + _p.senderAddress, _origin, _p.apparentValue, _gasPrice, _p.data, &c, codeHash, + version, m_depth, false, _p.staticCall); + } + } + + //////////////////////////////////////////////// // qtum + if(!m_s.addressInUse(_p.receiveAddress)) + m_sealEngine.deleteAddresses.insert(_p.receiveAddress); + //////////////////////////////////////////////// + + // Transfer ether. + m_s.transferBalance(_p.senderAddress, _p.receiveAddress, _p.valueTransfer); + return !m_ext; +} + +bool Executive::create(Address const& _txSender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin) +{ + // Contract will be created with the version corresponding to latest hard fork + auto const latestVersion = m_sealEngine.evmSchedule(m_envInfo.number()).accountVersion; + return createWithAddressFromNonceAndSender( + _txSender, _endowment, _gasPrice, _gas, _init, _origin, latestVersion); +} + +bool Executive::createOpcode(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin) +{ + // Contract will be created with the version equal to parent's version + return createWithAddressFromNonceAndSender( + _sender, _endowment, _gasPrice, _gas, _init, _origin, m_s.version(_sender)); +} + +bool Executive::createWithAddressFromNonceAndSender(Address const& _sender, u256 const& _endowment, + u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin, + u256 const& _version) +{ + u256 nonce = m_s.getNonce(_sender); + m_newAddress = right160(sha3(rlpList(_sender, nonce))); + return executeCreate(_sender, _endowment, _gasPrice, _gas, _init, _origin, _version); +} + +bool Executive::create2Opcode(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin, u256 const& _salt) +{ + m_newAddress = right160(sha3(bytes{0xff} +_sender.asBytes() + toBigEndian(_salt) + sha3(_init))); + // Contract will be created with the version equal to parent's version + return executeCreate( + _sender, _endowment, _gasPrice, _gas, _init, _origin, m_s.version(_sender)); +} + +bool Executive::executeCreate(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, + u256 const& _gas, bytesConstRef _init, Address const& _origin, u256 const& _version) +{ + if (_sender != MaxAddress || + m_envInfo.number() < m_sealEngine.chainParams().experimentalForkBlock) // EIP86 + m_s.incNonce(_sender); + + m_savepoint = m_s.savepoint(); + + m_isCreation = true; + + // We can allow for the reverted state (i.e. that with which m_ext is constructed) to contain the m_orig.address, since + // we delete it explicitly if we decide we need to revert. + + m_gas = _gas; + bool accountAlreadyExist = (m_s.addressHasCode(m_newAddress) || m_s.getNonce(m_newAddress) > 0); + if (accountAlreadyExist) + { + LOG(m_detailsLogger) << "Address already used: " << m_newAddress; + m_gas = 0; + m_excepted = TransactionException::AddressAlreadyUsed; + revert(); + m_ext = {}; // cancel the _init execution if there are any scheduled. + return !m_ext; + } + + // Transfer ether before deploying the code. This will also create new + // account if it does not exist yet. + m_s.transferBalance(_sender, m_newAddress, _endowment); + + u256 newNonce = m_s.requireAccountStartNonce(); + if (m_envInfo.number() >= m_sealEngine.chainParams().EIP158ForkBlock) + newNonce += 1; + m_s.setNonce(m_newAddress, newNonce); + + m_s.clearStorage(m_newAddress); + + // Schedule _init execution if not empty. + if (!_init.empty()) + m_ext = make_shared(m_s, m_envInfo, m_sealEngine, m_newAddress, _sender, _origin, + _endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), _version, m_depth, true, + false); + else + // code stays empty, but we set the version + m_s.setCode(m_newAddress, {}, _version); + + return !m_ext; +} + +OnOpFunc Executive::simpleTrace() +{ + Logger& traceLogger = m_vmTraceLogger; + + return [&traceLogger](uint64_t steps, uint64_t PC, Instruction inst, bigint newMemSize, + bigint gasCost, bigint gas, VMFace const* _vm, ExtVMFace const* voidExt) { + ExtVM const& ext = *static_cast(voidExt); + (void)inst; + (void)_vm; + + LOG(traceLogger) << dumpStorage(ext); + LOG(traceLogger) << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps + << " : " << hex << setw(4) << setfill('0') << PC << " : " + << dec << gas << " : -" << dec + << gasCost << " : " << newMemSize << "x32" + << " >"; + }; +} + +bool Executive::go(OnOpFunc const& _onOp) +{ + if (m_ext) + { +#if ETH_TIMED_EXECUTIONS + Timer t; +#endif + try + { + // Create VM instance. Force Interpreter if tracing requested. + auto vm = VMFactory::create(); + if (m_isCreation) + { + auto out = vm->exec(m_gas, *m_ext, _onOp); + if (m_res) + { + m_res->gasForDeposit = m_gas; + m_res->depositSize = out.size(); + } + if (out.size() > m_ext->evmSchedule().maxCodeSize) + BOOST_THROW_EXCEPTION(OutOfGas()); + else if(m_ext->evmSchedule().eip1559Mode && out.size() > 0 && out[0] == 0xEF) + BOOST_THROW_EXCEPTION(InvalidCode()); + else if (out.size() * m_ext->evmSchedule().createDataGas <= m_gas) + { + if (m_res) + m_res->codeDeposit = CodeDeposit::Success; + m_gas -= out.size() * m_ext->evmSchedule().createDataGas; + } + else + { + if (m_ext->evmSchedule().exceptionalFailedCodeDeposit) + BOOST_THROW_EXCEPTION(OutOfGas()); + else + { + if (m_res) + m_res->codeDeposit = CodeDeposit::Failed; + out = {}; + } + } + if (m_res) + m_res->output = out.toVector(); // copy output to execution result + m_s.setCode(m_ext->myAddress, out.toVector(), m_ext->version); + } + else + m_output = vm->exec(m_gas, *m_ext, _onOp); + } + catch (RevertInstruction& _e) + { + revert(); + m_output = _e.output(); + m_excepted = TransactionException::RevertInstruction; + } + catch (VMException const& _e) + { + LOG(m_detailsLogger) << "Safe VM Exception. " << diagnostic_information(_e); + m_gas = 0; + m_excepted = toTransactionException(_e); + revert(); + } + catch (InternalVMError const& _e) + { + cerror << "Internal VM Error (EVMC status code: " + << *boost::get_error_info(_e) << ")"; + revert(); + throw; + } + catch (Exception const& _e) + { + // TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does. + cerror << "Unexpected exception in VM. There may be a bug in this implementation. " + << diagnostic_information(_e); + exit(1); + // Another solution would be to reject this transaction, but that also + // has drawbacks. Essentially, the amount of ram has to be increased here. + } + catch (std::exception const& _e) + { + // TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does. + cerror << "Unexpected std::exception in VM. Not enough RAM? " << _e.what(); + exit(1); + // Another solution would be to reject this transaction, but that also + // has drawbacks. Essentially, the amount of ram has to be increased here. + } + + if (m_res && m_output) + // Copy full output: + m_res->output = m_output.toVector(); + +#if ETH_TIMED_EXECUTIONS + cnote << "VM took:" << t.elapsed() << "; gas used: " << (sgas - m_endGas); +#endif + } + return true; +} + +bool Executive::finalize() +{ + if (m_ext) + { + // Accumulate refunds for selfdestructs. + m_ext->sub.refunds += + m_ext->evmSchedule().selfdestructRefundGas * m_ext->sub.selfdestructs.size(); + + // Refunds must be applied before the miner gets the fees. + assert(m_ext->sub.refunds >= 0); + int64_t maxRefund = (static_cast(m_t.gas()) - static_cast(m_gas)) / 2; + m_gas += min(maxRefund, m_ext->sub.refunds); + } + + if (m_t) + { + m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); + + u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); + m_s.addBalance(m_envInfo.author(), feesEarned); + } + + // Selfdestructs... + if (m_ext) + for (auto a: m_ext->sub.selfdestructs) + m_s.kill(a.first); + + // Logs... + if (m_ext) + m_logs = m_ext->sub.logs; + + if (m_res) // Collect results + { + m_res->gasUsed = gasUsed(); + m_res->excepted = m_excepted; // TODO: m_except is used only in ExtVM::call + m_res->newAddress = m_newAddress; + m_res->gasRefunded = m_ext ? m_ext->sub.refunds : 0; + } + return (m_excepted == TransactionException::None); +} + +void Executive::revert() +{ + if (m_ext) + m_ext->sub.clear(); + + // Set result address to the null one. + m_newAddress = {}; + m_s.rollback(m_savepoint); +} diff --git a/src/eth_client/libethereum/Executive.h b/src/eth_client/libethereum/Executive.h new file mode 100644 index 0000000000..b2ef6852db --- /dev/null +++ b/src/eth_client/libethereum/Executive.h @@ -0,0 +1,153 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "Transaction.h" +#include +#include +#include +#include + +namespace dev +{ + +class OverlayDB; + +namespace eth +{ + +class State; +class ExtVM; +class SealEngineFace; +struct Manifest; + +/** + * @brief Message-call/contract-creation executor; useful for executing transactions. + * + * Two ways of using this class - either as a transaction executive or a CALL/CREATE executive. + * + * In the first use, after construction, begin with initialize(), then execute() and end with finalize(). Call go() + * after execute() only if it returns false. + * + * In the second use, after construction, begin with call() or create() and end with + * accrueSubState(). Call go() after call()/create() only if it returns false. + * + * Example: + * @code + * Executive e(state, blockchain, 0); + * e.initialize(transaction); + * if (!e.execute()) + * e.go(); + * e.finalize(); + * @endcode + */ +class Executive +{ +public: + /// Simple constructor; executive will operate on given state, with the given environment info. + Executive(State& _s, EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, unsigned _level = 0): m_s(_s), m_envInfo(_envInfo), m_depth(_level), m_sealEngine(_sealEngine) {} + + Executive(Executive const&) = delete; + void operator=(Executive) = delete; + + /// Initializes the executive for evaluating a transaction. You must call finalize() at some point following this. + void initialize(bytesConstRef _transaction) { initialize(Transaction(_transaction, CheckTransaction::None)); } + void initialize(Transaction const& _transaction); + /// Finalise a transaction previously set up with initialize(). + /// @warning Only valid after initialize() and execute(), and possibly go(). + /// @returns true if the outermost execution halted normally, false if exceptionally halted. + bool finalize(); + /// Begins execution of a transaction. You must call finalize() following this. + /// @returns true if the transaction is done, false if go() must be called. + bool execute(); + /// @returns the transaction from initialize(). + /// @warning Only valid after initialize(). + Transaction const& t() const { return m_t; } + /// @returns the log entries created by this operation. + /// @warning Only valid after finalise(). + LogEntries const& logs() const { return m_logs; } + /// @returns total gas used in the transaction/operation. + /// @warning Only valid after finalise(). + u256 gasUsed() const; + + owning_bytes_ref takeOutput() { return std::move(m_output); } + + /// Set up the executive for evaluating a bare CREATE (contract-creation) operation. + /// @returns false iff go() must be called (and thus a VM execution in required). + bool create(Address const& _txSender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _code, Address const& _originAddress); + /// @returns false iff go() must be called (and thus a VM execution in required). + bool createOpcode(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _code, Address const& _originAddress); + /// @returns false iff go() must be called (and thus a VM execution in required). + bool create2Opcode(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _code, Address const& _originAddress, u256 const& _salt); + /// Set up the executive for evaluating a bare CALL (message call) operation. + /// @returns false iff go() must be called (and thus a VM execution in required). + bool call(Address const& _receiveAddress, Address const& _txSender, u256 const& _txValue, u256 const& _gasPrice, bytesConstRef _txData, u256 const& _gas); + bool call(CallParameters const& _cp, u256 const& _gasPrice, Address const& _origin); + /// Finalise an operation through accruing the substate into the parent context. + void accrueSubState(SubState& _parentContext); + + /// Executes (or continues execution of) the VM. + /// @returns false iff go() must be called again to finish the transaction. + bool go(OnOpFunc const& _onOp = OnOpFunc()); + + /// Operation function for providing a simple trace of the VM execution. + OnOpFunc simpleTrace(); + + /// @returns gas remaining after the transaction/operation. Valid after the transaction has been executed. + u256 gas() const { return m_gas; } + + /// @returns the new address for the created contract in the CREATE operation. + Address newAddress() const { return m_newAddress; } + + /// @returns The exception that has happened during the execution if any. + TransactionException getException() const noexcept { return m_excepted; } + + /// Collect execution results in the result storage provided. + void setResultRecipient(ExecutionResult& _res) { m_res = &_res; } + + /// Revert all changes made to the state by this execution. + void revert(); + + /// Used only in tests + ExtVM const& extVM() const { return *m_ext; } + +private: + /// @returns false iff go() must be called (and thus a VM execution in required). + bool createWithAddressFromNonceAndSender(Address const& _sender, u256 const& _endowment, + u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin, + u256 const& _version); + /// @returns false iff go() must be called (and thus a VM execution in required). + bool executeCreate(Address const& _txSender, u256 const& _endowment, u256 const& _gasPrice, + u256 const& _gas, bytesConstRef _code, Address const& _originAddress, u256 const& _version); + + State& m_s; ///< The state to which this operation/transaction is applied. + // TODO: consider changign to EnvInfo const& to avoid LastHashes copy at every CALL/CREATE + EnvInfo m_envInfo; ///< Information on the runtime environment. + std::shared_ptr m_ext; ///< The VM externality object for the VM execution or null if no VM is required. shared_ptr used only to allow ExtVM forward reference. This field does *NOT* survive this object. + owning_bytes_ref m_output; ///< Execution output. + ExecutionResult* m_res = nullptr; ///< Optional storage for execution results. + + unsigned m_depth = 0; ///< The context's call-depth. + TransactionException m_excepted = TransactionException::None; ///< Details if the VM's execution resulted in an exception. + int64_t m_baseGasRequired; ///< The base amount of gas requried for executing this transaction. + u256 m_gas = 0; ///< The gas for EVM code execution. Initial amount before go() execution, final amount after go() execution. + + Transaction m_t; ///< The original transaction. Set by setup(). + LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize(). + + u256 m_gasCost; + SealEngineFace const& m_sealEngine; + + bool m_isCreation = false; + Address m_newAddress; + size_t m_savepoint = 0; + + Logger m_execLogger{createLogger(VerbosityDebug, "exec")}; + Logger m_detailsLogger{createLogger(VerbosityTrace, "exec")}; + Logger m_vmTraceLogger{createLogger(VerbosityTrace, "vmtrace")}; +}; + +} +} diff --git a/src/eth_client/libethereum/ExtVM.cpp b/src/eth_client/libethereum/ExtVM.cpp new file mode 100644 index 0000000000..5b450e1724 --- /dev/null +++ b/src/eth_client/libethereum/ExtVM.cpp @@ -0,0 +1,200 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "ExtVM.h" +#include "LastBlockHashesFace.h" +#include +#include +#include + +using namespace dev; +using namespace dev::eth; + +namespace // anonymous +{ + +static unsigned const c_depthLimit = 1024; + +/// Upper bound of stack space needed by single CALL/CREATE execution. Set experimentally. +static size_t const c_singleExecutionStackSize = 100 * 1024; + +/// Standard thread stack size. +static size_t const c_defaultStackSize = +#if defined(__linux) + 8 * 1024 * 1024; +#elif defined(_WIN32) + 16 * 1024 * 1024; +#else + 512 * 1024; // OSX and other OSs +#endif + +/// Stack overhead prior to allocation. +static size_t const c_entryOverhead = 128 * 1024; + +/// On what depth execution should be offloaded to additional separated stack space. +static unsigned const c_offloadPoint = (c_defaultStackSize - c_entryOverhead) / c_singleExecutionStackSize; + +void goOnOffloadedStack(Executive& _e, OnOpFunc const& _onOp) +{ + // Set new stack size enouth to handle the rest of the calls up to the limit. + boost::thread::attributes attrs; + attrs.set_stack_size((c_depthLimit - c_offloadPoint) * c_singleExecutionStackSize); + + // Create new thread with big stack and join immediately. + // TODO: It is possible to switch the implementation to Boost.Context or similar when the API is stable. + boost::exception_ptr exception; + boost::thread{attrs, [&]{ + try + { + _e.go(_onOp); + } + catch (...) + { + exception = boost::current_exception(); // Catch all exceptions to be rethrown in parent thread. + } + }}.join(); + if (exception) + boost::rethrow_exception(exception); +} + +void go(unsigned _depth, Executive& _e, OnOpFunc const& _onOp) +{ + // If in the offloading point we need to switch to additional separated stack space. + // Current stack is too small to handle more CALL/CREATE executions. + // It needs to be done only once as newly allocated stack space it enough to handle + // the rest of the calls up to the depth limit (c_depthLimit). + + if (_depth == c_offloadPoint) + { + cnote << "Stack offloading (depth: " << c_offloadPoint << ")"; + goOnOffloadedStack(_e, _onOp); + } + else + _e.go(_onOp); +} + +evmc_status_code transactionExceptionToEvmcStatusCode(TransactionException ex) noexcept +{ + switch (ex) + { + case TransactionException::None: + return EVMC_SUCCESS; + + case TransactionException::RevertInstruction: + return EVMC_REVERT; + + case TransactionException::OutOfGas: + return EVMC_OUT_OF_GAS; + + case TransactionException::BadInstruction: + return EVMC_UNDEFINED_INSTRUCTION; + + case TransactionException::OutOfStack: + return EVMC_STACK_OVERFLOW; + + case TransactionException::StackUnderflow: + return EVMC_STACK_UNDERFLOW; + + case TransactionException ::BadJumpDestination: + return EVMC_BAD_JUMP_DESTINATION; + + default: + return EVMC_FAILURE; + } +} + +} // anonymous namespace + + +CallResult ExtVM::call(CallParameters& _p) +{ + Executive e{m_s, envInfo(), m_sealEngine, depth + 1}; + if (!e.call(_p, gasPrice, origin)) + { + go(depth, e, _p.onOp); + e.accrueSubState(sub); + } + _p.gas = e.gas(); + + return {transactionExceptionToEvmcStatusCode(e.getException()), e.takeOutput()}; +} + +size_t ExtVM::codeSizeAt(Address _a) +{ + return m_s.codeSize(_a); +} + +h256 ExtVM::codeHashAt(Address _a) +{ + return exists(_a) ? m_s.codeHash(_a) : h256{}; +} + +void ExtVM::setStore(u256 _n, u256 _v) +{ + m_s.setStorage(myAddress, _n, _v); +} + +CreateResult ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, Instruction _op, u256 _salt, OnOpFunc const& _onOp) +{ + Executive e{m_s, envInfo(), m_sealEngine, depth + 1}; + bool result = false; + if (_op == OP_CREATE) + result = e.createOpcode(myAddress, _endowment, gasPrice, io_gas, _code, origin); + else + { + assert(_op == OP_CREATE2); + result = e.create2Opcode(myAddress, _endowment, gasPrice, io_gas, _code, origin, _salt); + } + + if (!result) + { + go(depth, e, _onOp); + e.accrueSubState(sub); + } + io_gas = e.gas(); + return {transactionExceptionToEvmcStatusCode(e.getException()), e.takeOutput(), e.newAddress()}; +} + +bool ExtVM::selfdestruct(Address _a) +{ + // Why transfer is not used here? That caused a consensus issue before (see Quirk #2 in + // http://martin.swende.se/blog/Ethereum_quirks_and_vulns.html). There is one test case + // witnessing the current consensus + // 'GeneralStateTests/stSystemOperationsTest/suicideSendEtherPostDeath.json'. + if(!m_s.addressInUse(_a)){ + m_sealEngine.deleteAddresses.insert(_a); + } + m_s.transferBalance(myAddress, _a, m_s.balance(myAddress)); + return ExtVMFace::selfdestruct(_a); +} + +h256 ExtVM::blockHash(u256 _number) +{ + u256 const currentNumber = envInfo().number(); + + if (_number >= currentNumber || _number < (std::max(256, currentNumber) - 256)) + return h256(); + + if (currentNumber < m_sealEngine.chainParams().experimentalForkBlock + 256) + { + h256 const parentHash = envInfo().header().parentHash(); + h256s const lastHashes = envInfo().lastHashes().precedingHashes(parentHash); + + assert(lastHashes.size() > (unsigned)(currentNumber - 1 - _number)); + return lastHashes[(unsigned)(currentNumber - 1 - _number)]; + } + + u256 const nonce = m_s.getNonce(caller); + u256 const gas = 1000000; + Transaction tx(0, 0, gas, c_blockhashContractAddress, toBigEndian(_number), nonce); + tx.forceSender(caller); + + ExecutionResult res; + std::tie(res, std::ignore) = m_s.execute(envInfo(), m_sealEngine, tx, Permanence::Reverted); + return h256(res.output); +} + +bool ExtVM::isPrecompiled(Address _a) const +{ + return m_sealEngine.isPrecompiled(_a, envInfo().number()); +} diff --git a/src/eth_client/libethereum/ExtVM.h b/src/eth_client/libethereum/ExtVM.h new file mode 100644 index 0000000000..8d0d882cc8 --- /dev/null +++ b/src/eth_client/libethereum/ExtVM.h @@ -0,0 +1,118 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "Executive.h" +#include "State.h" + +#include +#include +#include + +#include +#include + +namespace dev +{ +namespace eth +{ + +class SealEngineFace; + +/// Externality interface for the Virtual Machine providing access to world state. +class ExtVM : public ExtVMFace +{ +public: + /// Full constructor. + ExtVM(State& _s, EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Address _myAddress, + Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, + bytesConstRef _code, h256 const& _codeHash, u256 const& _version, unsigned _depth, + bool _isCreate, bool _staticCall) + : ExtVMFace(_envInfo, _myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), + _codeHash, _version, _depth, _isCreate, _staticCall), + m_s(_s), + m_sealEngine(_sealEngine), + m_evmSchedule(initEvmSchedule(envInfo().number(), _version)) + { + // Contract: processing account must exist. In case of CALL, the ExtVM + // is created only if an account has code (so exist). In case of CREATE + // the account must be created first. + assert(m_s.addressInUse(_myAddress)); + } + + /// Read storage location. + u256 store(u256 _n) final { return m_s.storage(myAddress, _n); } + + /// Write a value in storage. + void setStore(u256 _n, u256 _v) final; + + /// Read original storage value (before modifications in the current transaction). + u256 originalStorageValue(u256 const& _key) final + { + return m_s.originalStorageValue(myAddress, _key); + } + + /// Read address's code. + bytes const& codeAt(Address _a) final { return m_s.code(_a); } + + /// @returns the size of the code in bytes at the given address. + size_t codeSizeAt(Address _a) final; + + /// @returns the hash of the code at the given address. + h256 codeHashAt(Address _a) final; + + /// Create a new contract. + CreateResult create(u256 _endowment, u256& io_gas, bytesConstRef _code, Instruction _op, u256 _salt, OnOpFunc const& _onOp = {}) final; + + /// Create a new message call. + CallResult call(CallParameters& _params) final; + + /// Read address's balance. + u256 balance(Address _a) final { return m_s.balance(_a); } + + /// Does the account exist? + bool exists(Address _a) final + { + if (evmSchedule().emptinessIsNonexistence()) + return m_s.accountNonemptyAndExisting(_a); + else + return m_s.addressInUse(_a); + } + + /// Selfdestruct the associated contract to the given address. + bool selfdestruct(Address _a) final; + + /// Return the EVM gas-price schedule for this execution context. + EVMSchedule const& evmSchedule() const final { return m_evmSchedule; } + + State const& state() const { return m_s; } + + /// Hash of a block if within the last 256 blocks, or h256() otherwise. + h256 blockHash(u256 _number) final; + + /// Is the address from precompiled contract + bool isPrecompiled(Address _a) const final; + +private: + EVMSchedule const& initEvmSchedule(int64_t _blockNumber, u256 const& _version) const + { + // If _version is latest for the block, select corresponding latest schedule. + // Otherwise run with the latest schedule known to correspond to the _version. + EVMSchedule const& currentBlockSchedule = m_sealEngine.evmSchedule(_blockNumber); + if (currentBlockSchedule.accountVersion == _version) + return currentBlockSchedule; + else + return latestScheduleForAccountVersion(_version); + } + + + State& m_s; ///< A reference to the base state. + SealEngineFace const& m_sealEngine; + EVMSchedule const& m_evmSchedule; +}; + +} +} + diff --git a/src/eth_client/libethereum/LastBlockHashesFace.h b/src/eth_client/libethereum/LastBlockHashesFace.h new file mode 100644 index 0000000000..fd3dec84a6 --- /dev/null +++ b/src/eth_client/libethereum/LastBlockHashesFace.h @@ -0,0 +1,37 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +/// @file +/// Interface for getting a list of recent block hashes +#pragma once + +#include + + +namespace dev +{ + +namespace eth +{ + +/** +* @brief Interface for getting a list of recent block hashes +* @threadsafe +*/ +class LastBlockHashesFace +{ +public: + virtual ~LastBlockHashesFace() {} + + /// Get hashes of 256 consecutive blocks preceding and including @a _mostRecentHash + /// Hashes are returned in the order of descending height, + /// i.e. result[0] is @a _mostRecentHash, result[1] is its parent, result[2] is grandparent etc. + virtual h256s precedingHashes(h256 const& _mostRecentHash) const = 0; + + /// Clear any cached result + virtual void clear() = 0; +}; + +} +} diff --git a/src/eth_client/libethereum/SecureTrieDB.h b/src/eth_client/libethereum/SecureTrieDB.h new file mode 100644 index 0000000000..b414334752 --- /dev/null +++ b/src/eth_client/libethereum/SecureTrieDB.h @@ -0,0 +1,22 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include + +namespace dev +{ +namespace eth +{ +#if ETH_FATDB +template +using SecureTrieDB = SpecificTrieDB, KeyType>; +#else +template +using SecureTrieDB = SpecificTrieDB, KeyType>; +#endif + +} // namespace eth +} // namespace dev diff --git a/src/eth_client/libethereum/State.cpp b/src/eth_client/libethereum/State.cpp new file mode 100644 index 0000000000..9e36e0c092 --- /dev/null +++ b/src/eth_client/libethereum/State.cpp @@ -0,0 +1,811 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "State.h" + +#include "ExtVM.h" +#include "DatabasePaths.h" +#include +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; +namespace fs = boost::filesystem; + +State::State(u256 const& _accountStartNonce, OverlayDB const& _db, BaseState _bs): + m_db(_db), + m_state(&m_db), + m_accountStartNonce(_accountStartNonce) +{ + if (_bs != BaseState::PreExisting) + // Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly. + m_state.init(); +} + +State::State(State const& _s): + m_db(_s.m_db), + m_state(&m_db, _s.m_state.root(), Verification::Skip), + m_cache(_s.m_cache), + m_unchangedCacheEntries(_s.m_unchangedCacheEntries), + m_nonExistingAccountsCache(_s.m_nonExistingAccountsCache), + m_touched(_s.m_touched), + m_unrevertablyTouched(_s.m_unrevertablyTouched), + m_accountStartNonce(_s.m_accountStartNonce) +{} + +OverlayDB State::openDB(fs::path const& _basePath, h256 const& _genesisHash, WithExisting _we) +{ + DatabasePaths const dbPaths{_basePath, _genesisHash}; + if (db::isDiskDatabase()) + { + if (_we == WithExisting::Kill) + { + clog(VerbosityInfo, "statedb") << "Deleting state database: " << dbPaths.statePath(); + fs::remove_all(dbPaths.statePath()); + } + + clog(VerbosityDebug, "statedb") + << "Verifying path exists (and creating if not present): " << dbPaths.chainPath(); + fs::create_directories(dbPaths.chainPath()); + clog(VerbosityDebug, "statedb") + << "Ensuring permissions are set for path: " << dbPaths.chainPath(); + DEV_IGNORE_EXCEPTIONS(fs::permissions(dbPaths.chainPath(), fs::owner_all)); + } + + try + { + clog(VerbosityTrace, "statedb") << "Opening state database"; + std::unique_ptr db = db::DBFactory::create(dbPaths.statePath()); + return OverlayDB(std::move(db)); + } + catch (boost::exception const& ex) + { + if (db::isDiskDatabase()) + { + clog(VerbosityError, "statedb") + << "Error opening state database: " << dbPaths.statePath(); + db::DatabaseStatus const dbStatus = + *boost::get_error_info(ex); + if (fs::space(dbPaths.statePath()).available < 1024) + { + clog(VerbosityError, "statedb") + << "Not enough available space found on hard drive. Please free some up and " + "then re-run. Bailing."; + BOOST_THROW_EXCEPTION(NotEnoughAvailableSpace()); + } + else if (dbStatus == db::DatabaseStatus::Corruption) + { + clog(VerbosityError, "statedb") + << "Database corruption detected. Please see the exception for corruption " + "details. Exception: " + << boost::diagnostic_information(ex); + BOOST_THROW_EXCEPTION(DatabaseCorruption()); + } + else if (dbStatus == db::DatabaseStatus::IOError) + { + clog(VerbosityError, "statedb") << "Database already open. You appear to have " + "another instance of Aleth running."; + BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen()); + } + } + clog(VerbosityError, "statedb") + << "Unknown error encountered when opening state database. Exception details: " + << boost::diagnostic_information(ex); + throw; + } +} + +void State::populateFrom(AccountMap const& _map) +{ + eth::commit(_map, m_state); + commit(State::CommitBehaviour::KeepEmptyAccounts); +} + +u256 const& State::requireAccountStartNonce() const +{ + if (m_accountStartNonce == Invalid256) + BOOST_THROW_EXCEPTION(InvalidAccountStartNonceInState()); + return m_accountStartNonce; +} + +void State::noteAccountStartNonce(u256 const& _actual) +{ + if (m_accountStartNonce == Invalid256) + m_accountStartNonce = _actual; + else if (m_accountStartNonce != _actual) + BOOST_THROW_EXCEPTION(IncorrectAccountStartNonceInState()); +} + +void State::removeEmptyAccounts() +{ + for (auto& i: m_cache) + if (i.second.isDirty() && i.second.isEmpty()) + i.second.kill(); + + for (auto const& _address : m_unrevertablyTouched) + { + Account* a = account(_address); + if (a && a->isEmpty()) + a->kill(); + } +} + +State& State::operator=(State const& _s) +{ + if (&_s == this) + return *this; + + m_db = _s.m_db; + m_state.open(&m_db, _s.m_state.root(), Verification::Skip); + m_cache = _s.m_cache; + m_unchangedCacheEntries = _s.m_unchangedCacheEntries; + m_nonExistingAccountsCache = _s.m_nonExistingAccountsCache; + m_touched = _s.m_touched; + m_unrevertablyTouched = _s.m_unrevertablyTouched; + m_accountStartNonce = _s.m_accountStartNonce; + return *this; +} + +Account const* State::account(Address const& _a) const +{ + return const_cast(this)->account(_a); +} + +Account* State::account(Address const& _addr) +{ + auto it = m_cache.find(_addr); + if (it != m_cache.end()) + return &it->second; + + if (m_nonExistingAccountsCache.count(_addr)) + return nullptr; + + // Populate basic info. + string stateBack = m_state.at(_addr); + if (stateBack.empty()) + { + m_nonExistingAccountsCache.insert(_addr); + return nullptr; + } + + clearCacheIfTooLarge(); + + RLP state(stateBack); + auto const nonce = state[0].toInt(); + auto const balance = state[1].toInt(); + auto const storageRoot = state[2].toHash(); + auto const codeHash = state[3].toHash(); + // version is 0 if absent from RLP + auto const version = state[4] ? state[4].toInt() : 0; + + auto i = m_cache.emplace(piecewise_construct, forward_as_tuple(_addr), + forward_as_tuple(nonce, balance, storageRoot, codeHash, version, Account::Unchanged)); + m_unchangedCacheEntries.push_back(_addr); + return &i.first->second; +} + +void State::clearCacheIfTooLarge() const +{ + // TODO: Find a good magic number + while (m_unchangedCacheEntries.size() > 1000) + { + // Remove a random element + // FIXME: Do not use random device as the engine. The random device should be only used to seed other engine. + size_t const randomIndex = std::uniform_int_distribution(0, m_unchangedCacheEntries.size() - 1)(dev::s_fixedHashEngine); + + Address const addr = m_unchangedCacheEntries[randomIndex]; + swap(m_unchangedCacheEntries[randomIndex], m_unchangedCacheEntries.back()); + m_unchangedCacheEntries.pop_back(); + + auto cacheEntry = m_cache.find(addr); + if (cacheEntry != m_cache.end() && !cacheEntry->second.isDirty()) + m_cache.erase(cacheEntry); + } +} + +void State::commit(CommitBehaviour _commitBehaviour) +{ + if (_commitBehaviour == CommitBehaviour::RemoveEmptyAccounts) + removeEmptyAccounts(); + m_touched += dev::eth::commit(m_cache, m_state); + m_changeLog.clear(); + m_cache.clear(); + m_unchangedCacheEntries.clear(); +} + +unordered_map State::addresses() const +{ +#if ETH_FATDB + unordered_map ret; + for (auto& i: m_cache) + if (i.second.isAlive()) + ret[i.first] = i.second.balance(); + for (auto const& i: m_state) + if (m_cache.find(i.first) == m_cache.end()) + ret[i.first] = RLP(i.second)[1].toInt(); + return ret; +#else + BOOST_THROW_EXCEPTION(InterfaceNotSupported() << errinfo_interface("State::addresses()")); +#endif +} + +std::pair State::addresses( + h256 const& _beginHash, size_t _maxResults) const +{ + AddressMap addresses; + h256 nextKey; + +#if ETH_FATDB + for (auto it = m_state.hashedLowerBound(_beginHash); it != m_state.hashedEnd(); ++it) + { + auto const address = Address(it.key()); + auto const itCachedAddress = m_cache.find(address); + + // skip if deleted in cache + if (itCachedAddress != m_cache.end() && itCachedAddress->second.isDirty() && + !itCachedAddress->second.isAlive()) + continue; + + // break when _maxResults fetched + if (addresses.size() == _maxResults) + { + nextKey = h256((*it).first); + break; + } + + h256 const hashedAddress((*it).first); + addresses[hashedAddress] = address; + } +#endif + + // get addresses from cache with hash >= _beginHash (both new and old touched, we can't + // distinguish them) and order by hash + AddressMap cacheAddresses; + for (auto const& addressAndAccount : m_cache) + { + auto const& address = addressAndAccount.first; + auto const addressHash = sha3(address); + auto const& account = addressAndAccount.second; + if (account.isDirty() && account.isAlive() && addressHash >= _beginHash) + cacheAddresses.emplace(addressHash, address); + } + + // merge addresses from DB and addresses from cache + addresses.insert(cacheAddresses.begin(), cacheAddresses.end()); + + // if some new accounts were created in cache we need to return fewer results + if (addresses.size() > _maxResults) + { + auto itEnd = std::next(addresses.begin(), _maxResults); + nextKey = itEnd->first; + addresses.erase(itEnd, addresses.end()); + } + + return {addresses, nextKey}; +} + + +void State::setRoot(h256 const& _r) +{ + m_cache.clear(); + m_unchangedCacheEntries.clear(); + m_nonExistingAccountsCache.clear(); +// m_touched.clear(); + m_state.setRoot(_r); +} + +bool State::addressInUse(Address const& _id) const +{ + return !!account(_id); +} + +bool State::accountNonemptyAndExisting(Address const& _address) const +{ + if (Account const* a = account(_address)) + return !a->isEmpty(); + else + return false; +} + +bool State::addressHasCode(Address const& _id) const +{ + if (auto a = account(_id)) + return a->codeHash() != EmptySHA3; + else + return false; +} + +u256 State::balance(Address const& _id) const +{ + if (auto a = account(_id)) + return a->balance(); + else + return 0; +} + +void State::incNonce(Address const& _addr) +{ + if (Account* a = account(_addr)) + { + auto oldNonce = a->nonce(); + a->incNonce(); + m_changeLog.emplace_back(_addr, oldNonce); + } + else + // This is possible if a transaction has gas price 0. + createAccount(_addr, Account(requireAccountStartNonce() + 1, 0)); +} + +void State::setNonce(Address const& _addr, u256 const& _newNonce) +{ + if (Account* a = account(_addr)) + { + auto oldNonce = a->nonce(); + a->setNonce(_newNonce); + m_changeLog.emplace_back(_addr, oldNonce); + } + else + // This is possible when a contract is being created. + createAccount(_addr, Account(_newNonce, 0)); +} + +void State::addBalance(Address const& _id, u256 const& _amount) +{ + if (Account* a = account(_id)) + { + // Log empty account being touched. Empty touched accounts are cleared + // after the transaction, so this event must be also reverted. + // We only log the first touch (not dirty yet), and only for empty + // accounts, as other accounts does not matter. + // TODO: to save space we can combine this event with Balance by having + // Balance and Balance+Touch events. + if (!a->isDirty() && a->isEmpty()) + m_changeLog.emplace_back(Change::Touch, _id); + + // Increase the account balance. This also is done for value 0 to mark + // the account as dirty. Dirty account are not removed from the cache + // and are cleared if empty at the end of the transaction. + a->addBalance(_amount); + } + else + createAccount(_id, {requireAccountStartNonce(), _amount}); + + if (_amount) + m_changeLog.emplace_back(Change::Balance, _id, _amount); +} + +void State::subBalance(Address const& _addr, u256 const& _value) +{ + if (_value == 0) + return; + + Account* a = account(_addr); + if (!a || a->balance() < _value) + // TODO: I expect this never happens. + BOOST_THROW_EXCEPTION(NotEnoughCash()); + + // Fall back to addBalance(). + addBalance(_addr, 0 - _value); +} + +void State::setBalance(Address const& _addr, u256 const& _value) +{ + Account* a = account(_addr); + u256 original = a ? a->balance() : 0; + + // Fall back to addBalance(). + addBalance(_addr, _value - original); +} + +void State::createContract(Address const& _address) +{ + createAccount(_address, {requireAccountStartNonce(), 0}); +} + +void State::createAccount(Address const& _address, Account const&& _account) +{ + assert(!addressInUse(_address) && "Account already exists"); + m_cache[_address] = std::move(_account); + m_nonExistingAccountsCache.erase(_address); + m_changeLog.emplace_back(Change::Create, _address); +} + +void State::kill(Address _addr) +{ + if (auto a = account(_addr)) + a->kill(); + // If the account is not in the db, nothing to kill. +} + +u256 State::getNonce(Address const& _addr) const +{ + if (auto a = account(_addr)) + return a->nonce(); + else + return m_accountStartNonce; +} + +u256 State::storage(Address const& _id, u256 const& _key) const +{ + if (Account const* a = account(_id)) + return a->storageValue(_key, m_db); + else + return 0; +} + +void State::setStorage(Address const& _contract, u256 const& _key, u256 const& _value) +{ + m_changeLog.emplace_back(_contract, _key, storage(_contract, _key)); + m_cache[_contract].setStorage(_key, _value); +} + +u256 State::originalStorageValue(Address const& _contract, u256 const& _key) const +{ + if (Account const* a = account(_contract)) + return a->originalStorageValue(_key, m_db); + else + return 0; +} + +void State::clearStorage(Address const& _contract) +{ + h256 const& oldHash{m_cache[_contract].baseRoot()}; + if (oldHash == EmptyTrie) + return; + m_changeLog.emplace_back(Change::StorageRoot, _contract, oldHash); + m_cache[_contract].clearStorage(); +} + +map> State::storage(Address const& _id) const +{ +#if ETH_FATDB + map> ret; + + if (Account const* a = account(_id)) + { + // Pull out all values from trie storage. + if (h256 root = a->baseRoot()) + { + SecureTrieDB memdb(const_cast(&m_db), root); // promise we won't alter the overlay! :) + + for (auto it = memdb.hashedBegin(); it != memdb.hashedEnd(); ++it) + { + h256 const hashedKey((*it).first); + u256 const key = h256(it.key()); + u256 const value = RLP((*it).second).toInt(); + ret[hashedKey] = make_pair(key, value); + } + } + + // Then merge cached storage over the top. + for (auto const& i : a->storageOverlay()) + { + h256 const key = i.first; + h256 const hashedKey = sha3(key); + if (i.second) + ret[hashedKey] = i; + else + ret.erase(hashedKey); + } + } + return ret; +#else + (void) _id; + BOOST_THROW_EXCEPTION(InterfaceNotSupported() << errinfo_interface("State::storage(Address const& _id)")); +#endif +} + +h256 State::storageRoot(Address const& _id) const +{ + string s = m_state.at(_id); + if (s.size()) + { + RLP r(s); + return r[2].toHash(); + } + return EmptyTrie; +} + +bytes const& State::code(Address const& _addr) const +{ + Account const* a = account(_addr); + if (!a || a->codeHash() == EmptySHA3) + return NullBytes; + + if (a->code().empty()) + { + // Load the code from the backend. + Account* mutableAccount = const_cast(a); + mutableAccount->noteCode(m_db.lookup(a->codeHash())); + CodeSizeCache::instance().store(a->codeHash(), a->code().size()); + } + + return a->code(); +} + +void State::setCode(Address const& _address, bytes&& _code, u256 const& _version) +{ + // rollback assumes that overwriting of the code never happens + // (not allowed in contract creation logic in Executive) + assert(!addressHasCode(_address)); + m_changeLog.emplace_back(Change::Code, _address); + m_cache[_address].setCode(move(_code), _version); +} + +h256 State::codeHash(Address const& _a) const +{ + if (Account const* a = account(_a)) + return a->codeHash(); + else + return EmptySHA3; +} + +size_t State::codeSize(Address const& _a) const +{ + if (Account const* a = account(_a)) + { + if (a->hasNewCode()) + return a->code().size(); + auto& codeSizeCache = CodeSizeCache::instance(); + h256 codeHash = a->codeHash(); + if (codeSizeCache.contains(codeHash)) + return codeSizeCache.get(codeHash); + else + { + size_t size = code(_a).size(); + codeSizeCache.store(codeHash, size); + return size; + } + } + else + return 0; +} + +u256 State::version(Address const& _a) const +{ + Account const* a = account(_a); + return a ? a->version() : 0; +} + +void State::unrevertableTouch(Address const& _address) +{ + m_unrevertablyTouched.insert(_address); +} + +size_t State::savepoint() const +{ + return m_changeLog.size(); +} + +void State::rollback(size_t _savepoint) +{ + while (_savepoint != m_changeLog.size()) + { + auto& change = m_changeLog.back(); + auto& account = m_cache[change.address]; + + // Public State API cannot be used here because it will add another + // change log entry. + switch (change.kind) + { + case Change::Storage: + account.setStorage(change.key, change.value); + break; + case Change::StorageRoot: + account.setStorageRoot(change.value); + break; + case Change::Balance: + account.addBalance(0 - change.value); + break; + case Change::Nonce: + account.setNonce(change.value); + break; + case Change::Create: + m_cache.erase(change.address); + break; + case Change::Code: + account.resetCode(); + break; + case Change::Touch: + account.untouch(); + m_unchangedCacheEntries.emplace_back(change.address); + break; + } + m_changeLog.pop_back(); + } +} + +std::pair State::execute(EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) +{ + // Create and initialize the executive. This will throw fairly cheaply and quickly if the + // transaction is bad in any way. + Executive e(*this, _envInfo, _sealEngine); + ExecutionResult res; + e.setResultRecipient(res); + + auto onOp = _onOp; + if (isVmTraceEnabled() && !onOp) + onOp = e.simpleTrace(); + + u256 const startGasUsed = _envInfo.gasUsed(); + bool const statusCode = executeTransaction(e, _t, onOp); + + bool removeEmptyAccounts = false; + switch (_p) + { + case Permanence::Reverted: + m_cache.clear(); + break; + case Permanence::Committed: + removeEmptyAccounts = _envInfo.number() >= _sealEngine.chainParams().EIP158ForkBlock; + commit(removeEmptyAccounts ? State::CommitBehaviour::RemoveEmptyAccounts : State::CommitBehaviour::KeepEmptyAccounts); + break; + case Permanence::Uncommitted: + break; + } + + TransactionReceipt const receipt = _envInfo.number() >= _sealEngine.chainParams().byzantiumForkBlock ? + TransactionReceipt(statusCode, startGasUsed + e.gasUsed(), e.logs()) : + TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs()); + return make_pair(res, receipt); +} + +/// @returns true when normally halted; false when exceptionally halted; throws when internal VM +/// exception occurred. +bool State::executeTransaction(Executive& _e, Transaction const& _t, OnOpFunc const& _onOp) +{ + size_t const savept = savepoint(); + try + { + _e.initialize(_t); + + if (!_e.execute()) + _e.go(_onOp); + return _e.finalize(); + } + catch (Exception const&) + { + rollback(savept); + throw; + } +} + +std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) +{ + _out << "--- " << _s.rootHash() << std::endl; + std::set
d; + std::set
dtr; + auto trie = SecureTrieDB(const_cast(&_s.m_db), _s.rootHash()); + for (auto i: trie) + d.insert(i.first), dtr.insert(i.first); + for (auto i: _s.m_cache) + d.insert(i.first); + + for (auto i: d) + { + auto it = _s.m_cache.find(i); + Account* cache = it != _s.m_cache.end() ? &it->second : nullptr; + string rlpString = dtr.count(i) ? trie.at(i) : ""; + RLP r(rlpString); + assert(cache || r); + + if (cache && !cache->isAlive()) + _out << "XXX " << i << std::endl; + else + { + string lead = (cache ? r ? " * " : " + " : " "); + if (cache && r && cache->nonce() == r[0].toInt() && cache->balance() == r[1].toInt()) + lead = " . "; + + stringstream contout; + + if ((cache && cache->codeHash() == EmptySHA3) || (!cache && r && (h256)r[3] != EmptySHA3)) + { + std::map mem; + std::set back; + std::set delta; + std::set cached; + if (r) + { + SecureTrieDB memdb(const_cast(&_s.m_db), r[2].toHash()); // promise we won't alter the overlay! :) + for (auto const& j: memdb) + mem[j.first] = RLP(j.second).toInt(), back.insert(j.first); + } + if (cache) + for (auto const& j: cache->storageOverlay()) + { + if ((!mem.count(j.first) && j.second) || (mem.count(j.first) && mem.at(j.first) != j.second)) + mem[j.first] = j.second, delta.insert(j.first); + else if (j.second) + cached.insert(j.first); + } + if (!delta.empty()) + lead = (lead == " . ") ? "*.* " : "*** "; + + contout << " @:"; + if (!delta.empty()) + contout << "???"; + else + contout << r[2].toHash(); + if (cache && cache->hasNewCode()) + contout << " $" << toHex(cache->code()); + else + contout << " $" << (cache ? cache->codeHash() : r[3].toHash()); + + for (auto const& j: mem) + if (j.second) + contout << std::endl << (delta.count(j.first) ? back.count(j.first) ? " * " : " + " : cached.count(j.first) ? " . " : " ") << std::hex << nouppercase << std::setw(64) << j.first << ": " << std::setw(0) << j.second ; + else + contout << std::endl << "XXX " << std::hex << nouppercase << std::setw(64) << j.first << ""; + } + else + contout << " [SIMPLE]"; + _out << lead << i << ": " << std::dec << (cache ? cache->nonce() : r[0].toInt()) << " #:" << (cache ? cache->balance() : r[1].toInt()) << contout.str() << std::endl; + } + } + return _out; +} + +template +AddressHash dev::eth::commit(AccountMap const& _cache, SecureTrieDB& _state) +{ + AddressHash ret; + for (auto const& i: _cache) + if (i.second.isDirty()) + { + if (!i.second.isAlive()) + _state.remove(i.first); + else + { + auto const version = i.second.version(); + + // version = 0: [nonce, balance, storageRoot, codeHash] + // version > 0: [nonce, balance, storageRoot, codeHash, version] + RLPStream s(version != 0 ? 5 : 4); + s << i.second.nonce() << i.second.balance(); + + if (i.second.storageOverlay().empty()) + { + assert(i.second.baseRoot()); + s.append(i.second.baseRoot()); + } + else + { + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); + for (auto const& j: i.second.storageOverlay()) + if (j.second) + storageDB.insert(j.first, rlp(j.second)); + else + storageDB.remove(j.first); + assert(storageDB.root()); + s.append(storageDB.root()); + } + + if (i.second.hasNewCode()) + { + h256 ch = i.second.codeHash(); + // Store the size of the code + CodeSizeCache::instance().store(ch, i.second.code().size()); + _state.db()->insert(ch, &i.second.code()); + s << ch; + } + else + s << i.second.codeHash(); + + if (version != 0) + s << i.second.version(); + + _state.insert(i.first, &s.out()); + } + ret.insert(i.first); + } + return ret; +} + + +template AddressHash dev::eth::commit(AccountMap const& _cache, SecureTrieDB& _state); +template AddressHash dev::eth::commit(AccountMap const& _cache, SecureTrieDB& _state); diff --git a/src/eth_client/libethereum/State.h b/src/eth_client/libethereum/State.h new file mode 100644 index 0000000000..b9133386f3 --- /dev/null +++ b/src/eth_client/libethereum/State.h @@ -0,0 +1,365 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2013-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include "Account.h" +#include "SecureTrieDB.h" +#include "Transaction.h" +#include "TransactionReceipt.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dev +{ + +namespace test { class ImportTest; class StateLoader; } + +namespace eth +{ + +// Import-specific errinfos +using errinfo_uncleIndex = boost::error_info; +using errinfo_currentNumber = boost::error_info; +using errinfo_uncleNumber = boost::error_info; +using errinfo_unclesExcluded = boost::error_info; +using errinfo_block = boost::error_info; +using errinfo_now = boost::error_info; + +using errinfo_transactionIndex = boost::error_info; + +using errinfo_vmtrace = boost::error_info; +using errinfo_receipts = boost::error_info>; +using errinfo_transaction = boost::error_info; +using errinfo_phase = boost::error_info; +using errinfo_required_LogBloom = boost::error_info; +using errinfo_got_LogBloom = boost::error_info; +using LogBloomRequirementError = boost::tuple; + +class State; +class TransactionQueue; +struct VerifiedBlockRef; + +enum class BaseState +{ + PreExisting, + Empty +}; + +enum class Permanence +{ + Reverted, + Committed, + Uncommitted ///< Uncommitted state for change log readings in tests. +}; + +DEV_SIMPLE_EXCEPTION(InvalidAccountStartNonceInState); +DEV_SIMPLE_EXCEPTION(IncorrectAccountStartNonceInState); + +class SealEngineFace; +class Executive; + +/// An atomic state changelog entry. +struct Change +{ + enum Kind: int + { + /// Account balance changed. Change::value contains the amount the + /// balance was increased by. + Balance, + + /// Account storage was modified. Change::key contains the storage key, + /// Change::value the storage value. + Storage, + + /// Account storage root was modified. Change::value contains the old + /// account storage root. + StorageRoot, + + /// Account nonce was changed. + Nonce, + + /// Account was created (it was not existing before). + Create, + + /// New code was added to an account (by "create" message execution). + Code, + + /// Account was touched for the first time. + Touch + }; + + Kind kind; ///< The kind of the change. + Address address; ///< Changed account address. + u256 value; ///< Change value, e.g. balance, storage and nonce. + u256 key; ///< Storage key. Last because used only in one case. + + /// Helper constructor to make change log update more readable. + Change(Kind _kind, Address const& _addr, u256 const& _value = 0): + kind(_kind), address(_addr), value(_value) + { + } + + /// Helper constructor especially for storage change log. + Change(Address const& _addr, u256 const& _key, u256 const& _value): + kind(Storage), address(_addr), value(_value), key(_key) + {} + + /// Helper constructor for nonce change log. + Change(Address const& _addr, u256 const& _value): + kind(Nonce), address(_addr), value(_value) + {} +}; + +using ChangeLog = std::vector; + +/** + * Model of an Ethereum state, essentially a facade for the trie. + * + * Allows you to query the state of accounts as well as creating and modifying + * accounts. It has built-in caching for various aspects of the state. + * + * # State Changelog + * + * Any atomic change to any account is registered and appended in the changelog. + * In case some changes must be reverted, the changes are popped from the + * changelog and undone. For possible atomic changes list @see Change::Kind. + * The changelog is managed by savepoint(), rollback() and commit() methods. + */ +class State +{ + friend class ExtVM; + friend class dev::test::ImportTest; + friend class dev::test::StateLoader; + +public: + enum class CommitBehaviour + { + KeepEmptyAccounts, + RemoveEmptyAccounts + }; + + using AddressMap = std::map; + + /// Default constructor; creates with a blank database prepopulated with the genesis block. + explicit State(u256 const& _accountStartNonce): State(_accountStartNonce, OverlayDB(), BaseState::Empty) {} + + /// Basic state object from database. + /// Use the default when you already have a database and you just want to make a State object + /// which uses it. If you have no preexisting database then set BaseState to something other + /// than BaseState::PreExisting in order to prepopulate the Trie. + explicit State(u256 const& _accountStartNonce, OverlayDB const& _db, BaseState _bs = BaseState::PreExisting); + + enum NullType { Null }; + State(NullType): State(Invalid256, OverlayDB(), BaseState::Empty) {} + + /// Copy state object. + State(State const& _s); + + /// Copy state object. + State& operator=(State const& _s); + + /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. + static OverlayDB openDB(boost::filesystem::path const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + OverlayDB const& db() const { return m_db; } + OverlayDB& db() { return m_db; } + + /// Populate the state from the given AccountMap. Just uses dev::eth::commit(). + void populateFrom(AccountMap const& _map); + + /// @returns the set containing all addresses currently in use in Ethereum. + /// @warning This is slowslowslow. Don't use it unless you want to lock the object for seconds or minutes at a time. + /// @throws InterfaceNotSupported if compiled without ETH_FATDB. + std::unordered_map addresses() const; + + /// @returns the map with maximum _maxResults elements containing hash->addresses and the next + /// address hash. This method faster then addresses() const; + std::pair addresses(h256 const& _begin, size_t _maxResults) const; + + /// Execute a given transaction. + /// This will change the state accordingly. + std::pair execute(EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); + + /// Check if the address is in use. + bool addressInUse(Address const& _address) const; + + /// Check if the account exists in the state and is non empty (nonce > 0 || balance > 0 || code nonempty). + /// These two notions are equivalent after EIP158. + bool accountNonemptyAndExisting(Address const& _address) const; + + /// Check if the address contains executable code. + bool addressHasCode(Address const& _address) const; + + /// Get an account's balance. + /// @returns 0 if the address has never been used. + u256 balance(Address const& _id) const; + + /// Add some amount to balance. + /// Will initialise the address if it has never been used. + virtual void addBalance(Address const& _id, u256 const& _amount); // qtum + + /// Subtract the @p _value amount from the balance of @p _addr account. + /// @throws NotEnoughCash if the balance of the account is less than the + /// amount to be subtrackted (also in case the account does not exist). + void subBalance(Address const& _addr, u256 const& _value); + + /// Set the balance of @p _addr to @p _value. + /// Will instantiate the address if it has never been used. + void setBalance(Address const& _addr, u256 const& _value); + + /** + * @brief Transfers "the balance @a _value between two accounts. + * @param _from Account from which @a _value will be deducted. + * @param _to Account to which @a _value will be added. + * @param _value Amount to be transferred. + */ + virtual void transferBalance(Address const& _from, Address const& _to, u256 const& _value) { subBalance(_from, _value); addBalance(_to, _value); } + + /// Get the root of the storage of an account. + h256 storageRoot(Address const& _contract) const; + + /// Get the value of a storage position of an account. + /// @returns 0 if no account exists at that address. + u256 storage(Address const& _contract, u256 const& _memory) const; + + /// Set the value of a storage position of an account. + void setStorage(Address const& _contract, u256 const& _location, u256 const& _value); + + /// Get the original value of a storage position of an account (before modifications saved in + /// account cache). + /// @returns 0 if no account exists at that address. + u256 originalStorageValue(Address const& _contract, u256 const& _key) const; + + /// Clear the storage root hash of an account to the hash of the empty trie. + void clearStorage(Address const& _contract); + + /// Create a contract at the given address (with unset code and unchanged balance). + void createContract(Address const& _address); + + /// Sets the code of the account. Must only be called during / after contract creation. + void setCode(Address const& _address, bytes&& _code, u256 const& _version); + + /// Delete an account (used for processing selfdestructs). + virtual void kill(Address _a); + + /// Get the storage of an account. + /// @note This is expensive. Don't use it unless you need to. + /// @returns map of hashed keys to key-value pairs or empty map if no account exists at that address. + std::map> storage(Address const& _contract) const; + + /// Get the code of an account. + /// @returns bytes() if no account exists at that address. + /// @warning The reference to the code is only valid until the access to + /// other account. Do not keep it. + bytes const& code(Address const& _addr) const; + + /// Get the code hash of an account. + /// @returns EmptySHA3 if no account exists at that address or if there is no code associated with the address. + h256 codeHash(Address const& _contract) const; + + /// Get the byte-size of the code of an account. + /// @returns code(_contract).size(), but utilizes CodeSizeHash. + size_t codeSize(Address const& _contract) const; + + /// Get contract account's version. + /// @returns 0 if no account exists at that address. + u256 version(Address const& _contract) const; + + /// Increament the account nonce. + void incNonce(Address const& _id); + + /// Set the account nonce. + void setNonce(Address const& _addr, u256 const& _newNonce); + + /// Get the account nonce -- the number of transactions it has sent. + /// @returns 0 if the address has never been used. + u256 getNonce(Address const& _addr) const; + + /// The hash of the root of our state tree. + h256 rootHash() const { return m_state.root(); } + + /// Commit all changes waiting in the address cache to the DB. + /// @param _commitBehaviour whether or not to remove empty accounts during commit. + void commit(CommitBehaviour _commitBehaviour); + + /// Resets any uncommitted changes to the cache. + void setRoot(h256 const& _root); + + /// Get the account start nonce. May be required. + u256 const& accountStartNonce() const { return m_accountStartNonce; } + u256 const& requireAccountStartNonce() const; + void noteAccountStartNonce(u256 const& _actual); + + /// Mark account as touched and keep it touched even in case of rollback + void unrevertableTouch(Address const& _addr); + + /// Create a savepoint in the state changelog. + /// @return The savepoint index that can be used in rollback() function. + size_t savepoint() const; + + /// Revert all recent changes up to the given @p _savepoint savepoint. + void rollback(size_t _savepoint); + + ChangeLog const& changeLog() const { return m_changeLog; } + + virtual ~State(){} + +protected: + /// Turns all "touched" empty accounts into non-alive accounts. + void removeEmptyAccounts(); + + /// @returns the account at the given address or a null pointer if it does not exist. + /// The pointer is valid until the next access to the state or account. + Account const* account(Address const& _addr) const; + + /// @returns the account at the given address or a null pointer if it does not exist. + /// The pointer is valid until the next access to the state or account. + Account* account(Address const& _addr); + + /// Purges non-modified entries in m_cache if it grows too large. + void clearCacheIfTooLarge() const; + + void createAccount(Address const& _address, Account const&& _account); + + /// @returns true when normally halted; false when exceptionally halted; throws when internal VM + /// exception occurred. + bool executeTransaction(Executive& _e, Transaction const& _t, OnOpFunc const& _onOp); + + /// Our overlay for the state tree. + OverlayDB m_db; + /// Our state tree, as an OverlayDB DB. + SecureTrieDB m_state; + /// Our address cache. This stores the states of each address that has (or at least might have) + /// been changed. + mutable std::unordered_map m_cache; + /// Tracks entries in m_cache that can potentially be purged if it grows too large. + mutable std::vector
m_unchangedCacheEntries; + /// Tracks addresses that are known to not exist. + mutable std::set
m_nonExistingAccountsCache; + /// Tracks all addresses touched so far. + AddressHash m_touched; + /// Tracks addresses that were touched and should stay touched in case of rollback + AddressHash m_unrevertablyTouched; + + u256 m_accountStartNonce; + + friend std::ostream& operator<<(std::ostream& _out, State const& _s); + ChangeLog m_changeLog; +}; + +std::ostream& operator<<(std::ostream& _out, State const& _s); + +template +AddressHash commit(AccountMap const& _cache, SecureTrieDB& _state); + +} +} + diff --git a/src/eth_client/libethereum/Transaction.cpp b/src/eth_client/libethereum/Transaction.cpp new file mode 100644 index 0000000000..6b7d02cad2 --- /dev/null +++ b/src/eth_client/libethereum/Transaction.cpp @@ -0,0 +1,92 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include +#include +#include +#include +#include +#include +#include "Transaction.h" +using namespace std; +using namespace dev; +using namespace dev::eth; + +#define ETH_ADDRESS_DEBUG 0 + +std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _er) +{ + _out << "{" << _er.gasUsed << ", " << _er.newAddress << ", " << toHex(_er.output) << "}"; + return _out; +} + +TransactionException dev::eth::toTransactionException(Exception const& _e) +{ + // Basic Transaction exceptions + if (!!dynamic_cast(&_e)) + return TransactionException::BadRLP; + if (!!dynamic_cast(&_e)) + return TransactionException::OutOfGasIntrinsic; + if (!!dynamic_cast(&_e)) + return TransactionException::InvalidSignature; + // Executive exceptions + if (!!dynamic_cast(&_e)) + return TransactionException::OutOfGasBase; + if (!!dynamic_cast(&_e)) + return TransactionException::InvalidNonce; + if (!!dynamic_cast(&_e)) + return TransactionException::NotEnoughCash; + if (!!dynamic_cast(&_e)) + return TransactionException::BlockGasLimitReached; + if (!!dynamic_cast(&_e)) + return TransactionException::AddressAlreadyUsed; + // VM execution exceptions + if (!!dynamic_cast(&_e)) + return TransactionException::BadInstruction; + if (!!dynamic_cast(&_e)) + return TransactionException::BadJumpDestination; + if (!!dynamic_cast(&_e)) + return TransactionException::OutOfGas; + if (!!dynamic_cast(&_e)) + return TransactionException::OutOfStack; + if (!!dynamic_cast(&_e)) + return TransactionException::StackUnderflow; + if (!!dynamic_cast(&_e)) + return TransactionException::CreateWithValue; + if (!!dynamic_cast(&_e)) + return TransactionException::InvalidCode; + return TransactionException::Unknown; +} + +std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionException const& _er) +{ + switch (_er) + { + case TransactionException::None: _out << "None"; break; + case TransactionException::BadRLP: _out << "BadRLP"; break; + case TransactionException::InvalidFormat: _out << "InvalidFormat"; break; + case TransactionException::OutOfGasIntrinsic: _out << "OutOfGasIntrinsic"; break; + case TransactionException::InvalidSignature: _out << "InvalidSignature"; break; + case TransactionException::InvalidNonce: _out << "InvalidNonce"; break; + case TransactionException::NotEnoughCash: _out << "NotEnoughCash"; break; + case TransactionException::OutOfGasBase: _out << "OutOfGasBase"; break; + case TransactionException::BlockGasLimitReached: _out << "BlockGasLimitReached"; break; + case TransactionException::BadInstruction: _out << "BadInstruction"; break; + case TransactionException::BadJumpDestination: _out << "BadJumpDestination"; break; + case TransactionException::OutOfGas: _out << "OutOfGas"; break; + case TransactionException::OutOfStack: _out << "OutOfStack"; break; + case TransactionException::StackUnderflow: _out << "StackUnderflow"; break; + case TransactionException::CreateWithValue: _out << "CreateWithValue"; break; + case TransactionException::NoInformation: _out << "NoInformation"; break; + case TransactionException::RevertInstruction: _out << "Revert"; break; + case TransactionException::InvalidCode: _out << "InvalidCode"; break; + default: _out << "Unknown"; break; + } + return _out; +} + +Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig): + TransactionBase(_rlpData, _checkSig) +{ +} diff --git a/src/eth_client/libethereum/Transaction.h b/src/eth_client/libethereum/Transaction.h new file mode 100644 index 0000000000..1e26b40a0f --- /dev/null +++ b/src/eth_client/libethereum/Transaction.h @@ -0,0 +1,137 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ + +enum class TransactionException +{ + None = 0, + Unknown, + BadRLP, + InvalidFormat, + OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost. + InvalidSignature, + InvalidNonce, + NotEnoughCash, + OutOfGasBase, ///< Too little gas to pay for the base transaction cost. + BlockGasLimitReached, + BadInstruction, + BadJumpDestination, + OutOfGas, ///< Ran out of gas executing code of the transaction. + OutOfStack, ///< Ran out of stack executing code of the transaction. + StackUnderflow, + RevertInstruction, + InvalidZeroSignatureFormat, + AddressAlreadyUsed, + CreateWithValue, + NoInformation, + InvalidCode ///< EIP-3541 Invalid code: must not begin with 0xef. +}; + +enum class CodeDeposit +{ + None = 0, + Failed, + Success +}; + +struct VMException; + +TransactionException toTransactionException(Exception const& _e); +std::ostream& operator<<(std::ostream& _out, TransactionException const& _er); + +/// Description of the result of executing a transaction. +struct ExecutionResult +{ + u256 gasUsed = 0; + TransactionException excepted = TransactionException::Unknown; + Address newAddress; + bytes output; + CodeDeposit codeDeposit = CodeDeposit::None; ///< Failed if an attempted deposit failed due to lack of gas. + u256 gasRefunded = 0; + unsigned depositSize = 0; ///< Amount of code of the creation's attempted deposit. + u256 gasForDeposit; ///< Amount of gas remaining for the code deposit phase. +}; + +std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er); + +/// Encodes a transaction, ready to be exported to or freshly imported from RLP. +class Transaction: public TransactionBase +{ +public: + /// Constructs a null transaction. + Transaction() {} + + /// Constructs from a transaction skeleton & optional secret. + Transaction(TransactionSkeleton const& _ts, Secret const& _s = Secret()): TransactionBase(_ts, _s) {} + + /// Constructs a signed message-call transaction. + Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce, Secret const& _secret): + TransactionBase(_value, _gasPrice, _gas, _dest, _data, _nonce, _secret) + {} + + /// Constructs a signed contract-creation transaction. + Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce, Secret const& _secret): + TransactionBase(_value, _gasPrice, _gas, _data, _nonce, _secret) + {} + + /// Constructs an unsigned message-call transaction. + Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, Address const& _dest, bytes const& _data, u256 const& _nonce = Invalid256): + TransactionBase(_value, _gasPrice, _gas, _dest, _data, _nonce) + {} + + /// Constructs an unsigned contract-creation transaction. + Transaction(u256 const& _value, u256 const& _gasPrice, u256 const& _gas, bytes const& _data, u256 const& _nonce = Invalid256): + TransactionBase(_value, _gasPrice, _gas, _data, _nonce) + {} + + /// Constructs a transaction from the given RLP. + explicit Transaction(bytesConstRef _rlp, CheckTransaction _checkSig); + + /// Constructs a transaction from the given RLP. + explicit Transaction(bytes const& _rlp, CheckTransaction _checkSig): Transaction(&_rlp, _checkSig) {} +}; + +/// Nice name for vector of Transaction. +using Transactions = std::vector; + +class LocalisedTransaction: public Transaction +{ +public: + LocalisedTransaction( + Transaction const& _t, + h256 const& _blockHash, + unsigned _transactionIndex, + BlockNumber _blockNumber = 0 + ): + Transaction(_t), + m_blockHash(_blockHash), + m_transactionIndex(_transactionIndex), + m_blockNumber(_blockNumber) + {} + + h256 const& blockHash() const { return m_blockHash; } + unsigned transactionIndex() const { return m_transactionIndex; } + BlockNumber blockNumber() const { return m_blockNumber; } + +private: + h256 m_blockHash; + unsigned m_transactionIndex; + BlockNumber m_blockNumber; +}; + +} +} diff --git a/src/eth_client/libethereum/TransactionReceipt.cpp b/src/eth_client/libethereum/TransactionReceipt.cpp new file mode 100644 index 0000000000..937bfcd733 --- /dev/null +++ b/src/eth_client/libethereum/TransactionReceipt.cpp @@ -0,0 +1,103 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#include "TransactionReceipt.h" +#include + +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + +TransactionReceipt::TransactionReceipt(bytesConstRef _rlp) +{ + RLP r(_rlp); + if (!r.isList() || r.itemCount() != 4) + BOOST_THROW_EXCEPTION(InvalidTransactionReceiptFormat()); + + if (!r[0].isData()) + BOOST_THROW_EXCEPTION(InvalidTransactionReceiptFormat()); + + if (r[0].size() == 32) + m_statusCodeOrStateRoot = (h256)r[0]; + else if (r[0].isInt()) + m_statusCodeOrStateRoot = (uint8_t)r[0]; + else + BOOST_THROW_EXCEPTION(InvalidTransactionReceiptFormat()); + + m_gasUsed = (u256)r[1]; + m_bloom = (LogBloom)r[2]; + for (auto const& i : r[3]) + m_log.emplace_back(i); + +} + +TransactionReceipt::TransactionReceipt(h256 const& _root, u256 const& _gasUsed, LogEntries const& _log): + m_statusCodeOrStateRoot(_root), + m_gasUsed(_gasUsed), + m_bloom(eth::bloom(_log)), + m_log(_log) +{} + +TransactionReceipt::TransactionReceipt(uint8_t _status, u256 const& _gasUsed, LogEntries const& _log): + m_statusCodeOrStateRoot(_status), + m_gasUsed(_gasUsed), + m_bloom(eth::bloom(_log)), + m_log(_log) +{} + +void TransactionReceipt::streamRLP(RLPStream& _s) const +{ + _s.appendList(4); + if (hasStatusCode()) + _s << statusCode(); + else + _s << stateRoot(); + _s << m_gasUsed << m_bloom; + _s.appendList(m_log.size()); + for (LogEntry const& l: m_log) + l.streamRLP(_s); +} + +bool TransactionReceipt::hasStatusCode() const +{ + return m_statusCodeOrStateRoot.which() == 0; +} + +uint8_t TransactionReceipt::statusCode() const +{ + if (hasStatusCode()) + return boost::get(m_statusCodeOrStateRoot); + else + BOOST_THROW_EXCEPTION(TransactionReceiptVersionError()); +} + +h256 const& TransactionReceipt::stateRoot() const +{ + if (hasStatusCode()) + BOOST_THROW_EXCEPTION(TransactionReceiptVersionError()); + else + return boost::get(m_statusCodeOrStateRoot); +} + +std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionReceipt const& _r) +{ + if (_r.hasStatusCode()) + _out << "Status: " << _r.statusCode() << std::endl; + else + _out << "Root: " << _r.stateRoot() << std::endl; + _out << "Gas used: " << _r.cumulativeGasUsed() << std::endl; + _out << "Logs: " << _r.log().size() << " entries:" << std::endl; + for (LogEntry const& i: _r.log()) + { + _out << "Address " << i.address << ". Topics:" << std::endl; + for (auto const& j: i.topics) + _out << " " << j << std::endl; + _out << " Data: " << toHex(i.data) << std::endl; + } + _out << "Bloom: " << _r.bloom() << std::endl; + return _out; +} diff --git a/src/eth_client/libethereum/TransactionReceipt.h b/src/eth_client/libethereum/TransactionReceipt.h new file mode 100644 index 0000000000..e38e27ee61 --- /dev/null +++ b/src/eth_client/libethereum/TransactionReceipt.h @@ -0,0 +1,116 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + + +#pragma once + +#include +#include +#include + +#include +#include + +namespace dev +{ +namespace eth +{ + +/// Transaction receipt, constructed either from RLP representation or from individual values. +/// Either a state root or a status code is contained. m_hasStatusCode is true when it contains a status code. +/// Empty state root is not included into RLP-encoding. +class TransactionReceipt +{ +public: + TransactionReceipt(bytesConstRef _rlp); + TransactionReceipt(h256 const& _root, u256 const& _gasUsed, LogEntries const& _log); + TransactionReceipt(uint8_t _status, u256 const& _gasUsed, LogEntries const& _log); + + /// @returns true if the receipt has a status code. Otherwise the receipt has a state root (pre-EIP658). + bool hasStatusCode() const; + /// @returns the state root. + /// @throw TransactionReceiptVersionError when the receipt has a status code instead of a state root. + h256 const& stateRoot() const; + /// @returns the status code. + /// @throw TransactionReceiptVersionError when the receipt has a state root instead of a status code. + uint8_t statusCode() const; + u256 const& cumulativeGasUsed() const { return m_gasUsed; } + LogBloom const& bloom() const { return m_bloom; } + LogEntries const& log() const { return m_log; } + + void streamRLP(RLPStream& _s) const; + + bytes rlp() const { RLPStream s; streamRLP(s); return s.out(); } + +private: + boost::variant m_statusCodeOrStateRoot; + u256 m_gasUsed; + LogBloom m_bloom; + LogEntries m_log; +}; + +using TransactionReceipts = std::vector; + +std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r); + +class LocalisedTransactionReceipt: public TransactionReceipt +{ +public: + LocalisedTransactionReceipt( + TransactionReceipt const& _t, + h256 const& _hash, + h256 const& _blockHash, + BlockNumber _blockNumber, + Address const& _from, + Address const& _to, + unsigned _transactionIndex, + u256 const& _gasUsed, + Address const& _contractAddress = Address() + ): + TransactionReceipt(_t), + m_hash(_hash), + m_blockHash(_blockHash), + m_blockNumber(_blockNumber), + m_from(_from), + m_to(_to), + m_transactionIndex(_transactionIndex), + m_gasUsed(_gasUsed), + m_contractAddress(_contractAddress) + { + LogEntries entries = log(); + for (unsigned i = 0; i < entries.size(); i++) + m_localisedLogs.push_back(LocalisedLogEntry( + entries[i], + m_blockHash, + m_blockNumber, + m_hash, + m_transactionIndex, + i + )); + } + + h256 const& hash() const { return m_hash; } + h256 const& blockHash() const { return m_blockHash; } + BlockNumber blockNumber() const { return m_blockNumber; } + Address const& from() const { return m_from; } + Address const& to() const { return m_to; } + unsigned transactionIndex() const { return m_transactionIndex; } + u256 const& gasUsed() const { return m_gasUsed; } + Address const& contractAddress() const { return m_contractAddress; } + LocalisedLogEntries const& localisedLogs() const { return m_localisedLogs; }; + +private: + h256 m_hash; + h256 m_blockHash; + BlockNumber m_blockNumber; + Address m_from; + Address m_to; + unsigned m_transactionIndex = 0; + u256 m_gasUsed; + Address m_contractAddress; + LocalisedLogEntries m_localisedLogs; +}; + +} +} diff --git a/src/eth_client/libethereum/ValidationSchemes.cpp b/src/eth_client/libethereum/ValidationSchemes.cpp new file mode 100644 index 0000000000..f526e2521e --- /dev/null +++ b/src/eth_client/libethereum/ValidationSchemes.cpp @@ -0,0 +1,148 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "ValidationSchemes.h" +#include +#include + +using namespace std; +namespace js = json_spirit; + +namespace dev +{ +namespace eth +{ +namespace validation +{ +string const c_sealEngine = "sealEngine"; +string const c_params = "params"; +string const c_genesis = "genesis"; +string const c_accounts = "accounts"; +string const c_balance = "balance"; +string const c_wei = "wei"; +string const c_finney = "finney"; +string const c_author = "author"; +string const c_coinbase = "coinbase"; +string const c_nonce = "nonce"; +string const c_gasLimit = "gasLimit"; +string const c_timestamp = "timestamp"; +string const c_difficulty = "difficulty"; +string const c_extraData = "extraData"; +string const c_mixHash = "mixHash"; +string const c_parentHash = "parentHash"; +string const c_precompiled = "precompiled"; +string const c_code = "code"; +string const c_storage = "storage"; +string const c_gasUsed = "gasUsed"; +string const c_codeFromFile = "codeFromFile"; ///< A file containg a code as bytes. +string const c_shouldnotexist = "shouldnotexist"; + +string const c_minGasLimit = "minGasLimit"; +string const c_maxGasLimit = "maxGasLimit"; +string const c_gasLimitBoundDivisor = "gasLimitBoundDivisor"; +string const c_forkBlockSuffix = "ForkBlock"; +string const c_homesteadForkBlock = "homesteadForkBlock"; +string const c_daoHardforkBlock = "daoHardforkBlock"; +string const c_EIP150ForkBlock = "EIP150ForkBlock"; +string const c_EIP158ForkBlock = "EIP158ForkBlock"; +string const c_byzantiumForkBlock = "byzantiumForkBlock"; +string const c_eWASMForkBlock = "eWASMForkBlock"; +string const c_constantinopleForkBlock = "constantinopleForkBlock"; +string const c_constantinopleFixForkBlock = "constantinopleFixForkBlock"; +string const c_istanbulForkBlock = "istanbulForkBlock"; +string const c_muirGlacierForkBlock = "muirGlacierForkBlock"; +string const c_berlinForkBlock = "berlinForkBlock"; +string const c_londonForkBlock = "londonForkBlock"; +string const c_experimentalForkBlock = "experimentalForkBlock"; +string const c_accountStartNonce = "accountStartNonce"; +string const c_maximumExtraDataSize = "maximumExtraDataSize"; +string const c_tieBreakingGas = "tieBreakingGas"; +string const c_blockReward = "blockReward"; +string const c_difficultyBoundDivisor = "difficultyBoundDivisor"; +string const c_minimumDifficulty = "minimumDifficulty"; +string const c_durationLimit = "durationLimit"; +string const c_chainID = "chainID"; +string const c_networkID = "networkID"; +string const c_allowFutureBlocks = "allowFutureBlocks"; +string const c_qip6ForkBlock = "qip6ForkBlock"; +string const c_shanghaiForkBlock = "shanghaiForkBlock"; + +void validateConfigJson(js::mObject const& _obj) +{ + requireJsonFields(_obj, "ChainParams::loadConfig", + {{c_sealEngine, {{js::str_type}, JsonFieldPresence::Required}}, + {c_params, {{js::obj_type}, JsonFieldPresence::Required}}, + {c_genesis, {{js::obj_type}, JsonFieldPresence::Required}}, + {c_accounts, {{js::obj_type}, JsonFieldPresence::Optional}}}); + + requireJsonFields(_obj.at(c_genesis).get_obj(), "ChainParams::loadConfig::genesis", + {{c_author, {{js::str_type}, JsonFieldPresence::Required}}, + {c_nonce, {{js::str_type}, JsonFieldPresence::Required}}, + {c_gasLimit, {{js::str_type}, JsonFieldPresence::Required}}, + {c_timestamp, {{js::str_type}, JsonFieldPresence::Required}}, + {c_difficulty, {{js::str_type}, JsonFieldPresence::Required}}, + {c_extraData, {{js::str_type}, JsonFieldPresence::Required}}, + {c_mixHash, {{js::str_type}, JsonFieldPresence::Required}}, + {c_parentHash, {{js::str_type}, JsonFieldPresence::Optional}}}); + + if (_obj.count(c_accounts) != 0) + { + js::mObject const& accounts = _obj.at(c_accounts).get_obj(); + for (auto const& acc : accounts) + validateAccountObj(acc.second.get_obj()); + } +} + +void validateAccountMaskObj(js::mObject const& _obj) +{ + // A map object with possibly defined fields + requireJsonFields(_obj, "validateAccountMaskObj", + {{c_storage, {{js::obj_type}, JsonFieldPresence::Optional}}, + {c_balance, {{js::str_type}, JsonFieldPresence::Optional}}, + {c_nonce, {{js::str_type}, JsonFieldPresence::Optional}}, + {c_code, {{js::str_type}, JsonFieldPresence::Optional}}, + {c_precompiled, {{js::obj_type}, JsonFieldPresence::Optional}}, + {c_shouldnotexist, {{js::str_type}, JsonFieldPresence::Optional}}, + {c_wei, {{js::str_type}, JsonFieldPresence::Optional}}}); +} + +void validateAccountObj(js::mObject const& _obj) +{ + // Extendable account description. Check typo errors and fields type. + requireJsonFields(_obj, "validateAccountObj", + {{c_code, {{js::str_type}, JsonFieldPresence::Optional}}, + {c_nonce, {{js::str_type}, JsonFieldPresence::Optional}}, + {c_storage, {{js::obj_type}, JsonFieldPresence::Optional}}, + {c_balance, {{js::str_type}, JsonFieldPresence::Optional}}, + {c_wei, {{js::str_type}, JsonFieldPresence::Optional}}, + {c_codeFromFile, {{js::str_type}, JsonFieldPresence::Optional}}, + // "precompiled" accounts in configs are deprecated + {c_precompiled, {{js::obj_type}, JsonFieldPresence::Optional}}}); + + // At least one field must be set + if (_obj.empty()) + { + string comment = + "Error in validateAccountObj: At least one field must be set (code, nonce, " + "storage, balance, wei, codeFromFile)!"; + BOOST_THROW_EXCEPTION(MissingField() << errinfo_comment(comment)); + } + + // c_code, c_codeFromFile could not coexist + if (_obj.count(c_code) && _obj.count(c_codeFromFile)) + { + string comment = + "Error in validateAccountObj: field 'code' contradicts field 'codeFromFile'!"; + BOOST_THROW_EXCEPTION(UnknownField() << errinfo_comment(comment)); + } + + // c_wei, c_balance could not coexist + if (_obj.count(c_wei) && _obj.count(c_balance)) + { + string comment = "Error in validateAccountObj: field 'balance' contradicts field 'wei'!"; + BOOST_THROW_EXCEPTION(UnknownField() << errinfo_comment(comment)); + } +} +} +} +} diff --git a/src/eth_client/libethereum/ValidationSchemes.h b/src/eth_client/libethereum/ValidationSchemes.h new file mode 100644 index 0000000000..b49c6e3e2b --- /dev/null +++ b/src/eth_client/libethereum/ValidationSchemes.h @@ -0,0 +1,80 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2015-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace validation +{ +extern std::string const c_sealEngine; +extern std::string const c_params; +extern std::string const c_genesis; +extern std::string const c_accounts; +extern std::string const c_balance; +extern std::string const c_wei; +extern std::string const c_finney; +extern std::string const c_author; +extern std::string const c_coinbase; +extern std::string const c_nonce; +extern std::string const c_gasLimit; +extern std::string const c_timestamp; +extern std::string const c_difficulty; +extern std::string const c_extraData; +extern std::string const c_mixHash; +extern std::string const c_parentHash; +extern std::string const c_precompiled; +extern std::string const c_storage; +extern std::string const c_code; +extern std::string const c_gasUsed; +extern std::string const c_codeFromFile; +extern std::string const c_shouldnotexist; + +extern std::string const c_minGasLimit; +extern std::string const c_maxGasLimit; +extern std::string const c_gasLimitBoundDivisor; +extern std::string const c_forkBlockSuffix; +extern std::string const c_homesteadForkBlock; +extern std::string const c_daoHardforkBlock; +extern std::string const c_EIP150ForkBlock; +extern std::string const c_EIP158ForkBlock; +extern std::string const c_byzantiumForkBlock; +extern std::string const c_eWASMForkBlock; +extern std::string const c_constantinopleForkBlock; +extern std::string const c_constantinopleFixForkBlock; +extern std::string const c_istanbulForkBlock; +extern std::string const c_muirGlacierForkBlock; +extern std::string const c_berlinForkBlock; +extern std::string const c_londonForkBlock; +extern std::string const c_experimentalForkBlock; +extern std::string const c_accountStartNonce; +extern std::string const c_maximumExtraDataSize; +extern std::string const c_tieBreakingGas; +extern std::string const c_blockReward; +extern std::string const c_difficultyBoundDivisor; +extern std::string const c_minimumDifficulty; +extern std::string const c_durationLimit; +extern std::string const c_chainID; +extern std::string const c_networkID; +extern std::string const c_allowFutureBlocks; +extern std::string const c_qip6ForkBlock; +extern std::string const c_shanghaiForkBlock; + +// Validate config.json that contains chain params and genesis state +void validateConfigJson(json_spirit::mObject const& _obj); + +// Validate account json object +void validateAccountObj(json_spirit::mObject const& _o); + +// TODO move AccountMaskObj to libtesteth (it is used only in test logic) +// Validate accountMask json object. Mask indicates which fields are set +void validateAccountMaskObj(json_spirit::mObject const& _o); +} +} +} diff --git a/src/eth_client/libevm/EVMC.cpp b/src/eth_client/libevm/EVMC.cpp new file mode 100644 index 0000000000..5591d4b3c1 --- /dev/null +++ b/src/eth_client/libevm/EVMC.cpp @@ -0,0 +1,143 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#include "EVMC.h" + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace +{ +evmc_revision toRevision(EVMSchedule const& _schedule) noexcept +{ + if (_schedule.eip6049Mode) + return EVMC_SHANGHAI; + if (_schedule.eip1559Mode) + return EVMC_LONDON; + if (_schedule.eip2929Mode) + return EVMC_BERLIN; + if (_schedule.haveChainID) + return EVMC_ISTANBUL; + if (_schedule.haveCreate2 && !_schedule.eip1283Mode) + return EVMC_PETERSBURG; + if (_schedule.haveCreate2 && _schedule.eip1283Mode) + return EVMC_CONSTANTINOPLE; + if (_schedule.haveRevert) + return EVMC_BYZANTIUM; + if (_schedule.eip158Mode) + return EVMC_SPURIOUS_DRAGON; + if (_schedule.eip150Mode) + return EVMC_TANGERINE_WHISTLE; + if (_schedule.haveDelegateCall) + return EVMC_HOMESTEAD; + return EVMC_FRONTIER; +} +} // namespace + +EVMC::EVMC(evmc_vm* _vm, std::vector> const& _options) noexcept + : evmc::VM(_vm) +{ + assert(_vm != nullptr); + assert(is_abi_compatible()); + + // Set the options. + for (auto& pair : _options) + { + auto result = set_option(pair.first.c_str(), pair.second.c_str()); + switch (result) + { + case EVMC_SET_OPTION_SUCCESS: + break; + case EVMC_SET_OPTION_INVALID_NAME: + cwarn << "Unknown EVMC option '" << pair.first << "'"; + break; + case EVMC_SET_OPTION_INVALID_VALUE: + cwarn << "Invalid value '" << pair.second << "' for EVMC option '" << pair.first << "'"; + break; + default: + cwarn << "Unknown error when setting EVMC option '" << pair.first << "'"; + } + } +} + +owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp) +{ + assert(_ext.envInfo().number() >= 0); + assert(_ext.envInfo().timestamp() >= 0); + + constexpr int64_t int64max = std::numeric_limits::max(); + + // TODO: The following checks should be removed by changing the types + // used for gas, block number and timestamp. + (void)int64max; + assert(io_gas <= int64max); + assert(_ext.envInfo().gasLimit() <= int64max); + assert(_ext.depth <= static_cast(std::numeric_limits::max())); + + auto gas = static_cast(io_gas); + + auto mode = toRevision(_ext.evmSchedule()); + evmc_call_kind kind = _ext.isCreate ? EVMC_CREATE : EVMC_CALL; + uint32_t flags = _ext.staticCall ? EVMC_STATIC : 0; + assert(flags != EVMC_STATIC || kind == EVMC_CALL); // STATIC implies a CALL. + evmc_message msg = {kind, flags, static_cast(_ext.depth), gas, toEvmC(_ext.myAddress), + toEvmC(_ext.caller), _ext.data.data(), _ext.data.size(), toEvmC(_ext.value), + toEvmC(0x0_cppui256), toEvmC(_ext.myAddress)}; + EvmCHost host{_ext}; + auto r = execute(host, mode, msg, _ext.code.data(), _ext.code.size()); + // FIXME: Copy the output for now, but copyless version possible. + auto output = owning_bytes_ref{{&r.output_data[0], &r.output_data[r.output_size]}, 0, r.output_size}; + + switch (r.status_code) + { + case EVMC_SUCCESS: + io_gas = r.gas_left; + return output; + + case EVMC_REVERT: + io_gas = r.gas_left; + throw RevertInstruction{std::move(output)}; + + case EVMC_OUT_OF_GAS: + case EVMC_FAILURE: + BOOST_THROW_EXCEPTION(OutOfGas()); + + case EVMC_INVALID_INSTRUCTION: // NOTE: this could have its own exception + case EVMC_UNDEFINED_INSTRUCTION: + BOOST_THROW_EXCEPTION(BadInstruction()); + + case EVMC_BAD_JUMP_DESTINATION: + BOOST_THROW_EXCEPTION(BadJumpDestination()); + + case EVMC_STACK_OVERFLOW: + BOOST_THROW_EXCEPTION(OutOfStack()); + + case EVMC_STACK_UNDERFLOW: + BOOST_THROW_EXCEPTION(StackUnderflow()); + + case EVMC_INVALID_MEMORY_ACCESS: + BOOST_THROW_EXCEPTION(BufferOverrun()); + + case EVMC_STATIC_MODE_VIOLATION: + BOOST_THROW_EXCEPTION(DisallowedStateChange()); + + case EVMC_CREATE_WITH_VALUE: + BOOST_THROW_EXCEPTION(CreateWithValue()); + + case EVMC_REJECTED: + case EVMC_INTERNAL_ERROR: + default: + if (r.status_code <= EVMC_INTERNAL_ERROR) + BOOST_THROW_EXCEPTION(InternalVMError{} << errinfo_evmcStatusCode(r.status_code)); + else + // These cases aren't really internal errors, just more specific + // error codes returned by the VM. Map all of them to OOG. + BOOST_THROW_EXCEPTION(OutOfGas()); + } +} +} // namespace eth +} // namespace dev diff --git a/src/eth_client/libevm/EVMC.h b/src/eth_client/libevm/EVMC.h new file mode 100644 index 0000000000..3e7e954795 --- /dev/null +++ b/src/eth_client/libevm/EVMC.h @@ -0,0 +1,25 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#pragma once + +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ +/// The wrapper implementing the VMFace interface with a EVMC VM as a backend. +class EVMC : public evmc::VM, public VMFace +{ +public: + EVMC(evmc_vm* _vm, std::vector> const& _options) noexcept; + + owning_bytes_ref exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) final; +}; +} // namespace eth +} // namespace dev diff --git a/src/eth_client/libevm/ExtVMFace.cpp b/src/eth_client/libevm/ExtVMFace.cpp new file mode 100644 index 0000000000..02283490e9 --- /dev/null +++ b/src/eth_client/libevm/ExtVMFace.cpp @@ -0,0 +1,383 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "ExtVMFace.h" + +#include +#include +using namespace evmc; + +namespace dev +{ +namespace eth +{ +static_assert(sizeof(Address) == sizeof(evmc_address), "Address types size mismatch"); +static_assert(alignof(Address) == alignof(evmc_address), "Address types alignment mismatch"); +static_assert(sizeof(h256) == sizeof(evmc_uint256be), "Hash types size mismatch"); +static_assert(alignof(h256) == alignof(evmc_uint256be), "Hash types alignment mismatch"); + +bool EvmCHost::account_exists(evmc::address const& _addr) const noexcept +{ + record_account_access(_addr); + return m_extVM.exists(fromEvmC(_addr)); +} + +evmc::bytes32 EvmCHost::get_storage(evmc::address const& _addr, evmc::bytes32 const& _key) const + noexcept +{ + assert(fromEvmC(_addr) == m_extVM.myAddress); + record_account_access(_addr); + return toEvmC(m_extVM.store(fromEvmC(_key))); +} + +evmc_storage_status EvmCHost::set_storage( + evmc::address const& _addr, evmc::bytes32 const& _key, evmc::bytes32 const& _value) noexcept +{ + // Follow the EIP-2200 specification + // https://eips.ethereum.org/EIPS/eip-2200 + + assert(fromEvmC(_addr) == m_extVM.myAddress); + record_account_access(_addr); + u256 const index = fromEvmC(_key); + u256 const newValue = fromEvmC(_value); + u256 const currentValue = m_extVM.store(index); + + if (newValue == currentValue) + return EVMC_STORAGE_ASSIGNED; + + EVMSchedule const& schedule = m_extVM.evmSchedule(); + auto status = EVMC_STORAGE_MODIFIED; + u256 const originalValue = m_extVM.originalStorageValue(index); + if (originalValue == currentValue || !schedule.sstoreNetGasMetering()) + { + if (currentValue == 0) + status = EVMC_STORAGE_ADDED; + else if (newValue == 0) + { + status = EVMC_STORAGE_DELETED; + m_extVM.sub.refunds += schedule.sstoreRefundGas; + } + } + else + { + status = EVMC_STORAGE_ASSIGNED; + + ////////////////////////////////////////////////////////////////////////////////// + // Modification beck ported from mocked_host.hpp + + // Because we need to apply "both following clauses" + // we first collect information which clause is triggered + // then assign status code to combination of these clauses. + enum + { + None = 0, + RemoveClearsSchedule = 1 << 0, + AddClearsSchedule = 1 << 1, + RestoredBySet = 1 << 2, + RestoredByReset = 1 << 3, + }; + int triggered_clauses = None; + + // "If original value is not 0" + if (originalValue != 0) + { + // "If current value is 0" + if (currentValue == 0) + { + // "(also means that new value is not 0)" + assert(newValue != 0); + // "remove SSTORE_CLEARS_SCHEDULE gas from refund counter" + triggered_clauses |= RemoveClearsSchedule; + } + // "If new value is 0" + if (newValue == 0) + { + // "(also means that current value is not 0)" + assert(currentValue != 0); + // "add SSTORE_CLEARS_SCHEDULE gas to refund counter" + triggered_clauses |= AddClearsSchedule; + } + } + + // "If original value equals new value (this storage slot is reset)" + // Except: we use term 'storage slot restored'. + if (originalValue == newValue) + { + // "If original value is 0" + if (originalValue == 0) + { + // "add SSTORE_SET_GAS - SLOAD_GAS to refund counter" + triggered_clauses |= RestoredBySet; + } + // "Otherwise" + else + { + // "add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter" + triggered_clauses |= RestoredByReset; + } + } + + switch (triggered_clauses) + { + case RemoveClearsSchedule: + status = EVMC_STORAGE_DELETED_ADDED; + break; + case AddClearsSchedule: + status = EVMC_STORAGE_MODIFIED_DELETED; + break; + case RemoveClearsSchedule | RestoredByReset: + status = EVMC_STORAGE_DELETED_RESTORED; + break; + case RestoredBySet: + status = EVMC_STORAGE_ADDED_DELETED; + break; + case RestoredByReset: + status = EVMC_STORAGE_MODIFIED_RESTORED; + break; + case None: + status = EVMC_STORAGE_ASSIGNED; + break; + default: + assert(false); + } + ////////////////////////////////////////////////////////////////////////////////// + + if (originalValue != 0) + { + if (currentValue == 0) + m_extVM.sub.refunds -= schedule.sstoreRefundGas; // Can go negative. + if (newValue == 0) + m_extVM.sub.refunds += schedule.sstoreRefundGas; + } + if (originalValue == newValue) + { + if (originalValue == 0) + m_extVM.sub.refunds += schedule.sstoreSetGas - schedule.sstoreUnchangedGas; + else + m_extVM.sub.refunds += schedule.sstoreResetGas - schedule.sstoreUnchangedGas; + } + } + + m_extVM.setStore(index, newValue); // Interface uses native endianness + + return status; +} + +evmc::uint256be EvmCHost::get_balance(evmc::address const& _addr) const noexcept +{ + record_account_access(_addr); + return toEvmC(m_extVM.balance(fromEvmC(_addr))); +} + +size_t EvmCHost::get_code_size(evmc::address const& _addr) const noexcept +{ + record_account_access(_addr); + return m_extVM.codeSizeAt(fromEvmC(_addr)); +} + +evmc::bytes32 EvmCHost::get_code_hash(evmc::address const& _addr) const noexcept +{ + record_account_access(_addr); + return toEvmC(m_extVM.codeHashAt(fromEvmC(_addr))); +} + +size_t EvmCHost::copy_code(evmc::address const& _addr, size_t _codeOffset, byte* _bufferData, + size_t _bufferSize) const noexcept +{ + record_account_access(_addr); + Address addr = fromEvmC(_addr); + bytes const& c = m_extVM.codeAt(addr); + + // Handle "big offset" edge case. + if (_codeOffset >= c.size()) + return 0; + + size_t maxToCopy = c.size() - _codeOffset; + size_t numToCopy = std::min(maxToCopy, _bufferSize); + std::copy_n(&c[_codeOffset], numToCopy, _bufferData); + return numToCopy; +} + +bool EvmCHost::selfdestruct(evmc::address const& _addr, evmc::address const& _beneficiary) noexcept +{ + assert(fromEvmC(_addr) == m_extVM.myAddress); + record_account_access(_addr); + return m_extVM.selfdestruct(fromEvmC(_beneficiary)); +} + + +void EvmCHost::emit_log(evmc::address const& _addr, uint8_t const* _data, size_t _dataSize, + evmc::bytes32 const _topics[], size_t _numTopics) noexcept +{ + (void)_addr; + assert(fromEvmC(_addr) == m_extVM.myAddress); + h256 const* pTopics = reinterpret_cast(_topics); + m_extVM.log(h256s{pTopics, pTopics + _numTopics}, bytesConstRef{_data, _dataSize}); +} + +evmc_access_status EvmCHost::access_account(const evmc::address& addr) noexcept +{ + // Check if the address have been already accessed. + const auto already_accessed = accounts[addr].access_status; + + record_account_access(addr); + + // Accessing precompiled contracts is always warm. + if (m_extVM.isPrecompiled(fromEvmC(addr))) + return EVMC_ACCESS_WARM; + + return already_accessed; +} + +evmc_access_status EvmCHost::access_storage(const evmc::address& addr, + const evmc::bytes32& key) noexcept +{ + auto& value = accounts[addr].storage[key]; + const auto access_status = value.access_status; + value.access_status = EVMC_ACCESS_WARM; + return access_status; +} + +void EvmCHost::record_account_access(const evmc::address& addr) const +{ + EVMSchedule const& schedule = m_extVM.evmSchedule(); + if(schedule.accessStatus()) + accounts[addr].access_status = EVMC_ACCESS_WARM; +} + +evmc_tx_context EvmCHost::get_tx_context() const noexcept +{ + evmc_tx_context result = {}; + result.tx_gas_price = toEvmC(m_extVM.gasPrice); + result.tx_origin = toEvmC(m_extVM.origin); + + auto const& envInfo = m_extVM.envInfo(); + result.block_coinbase = toEvmC(envInfo.author()); + result.block_number = envInfo.number(); + result.block_timestamp = envInfo.timestamp(); + result.block_gas_limit = static_cast(envInfo.gasLimit()); + result.block_prev_randao = toEvmC(envInfo.difficulty()); + result.chain_id = toEvmC(envInfo.chainID()); + return result; +} + +evmc::bytes32 EvmCHost::get_block_hash(int64_t _number) const noexcept +{ + return toEvmC(m_extVM.blockHash(_number)); +} + +evmc::Result EvmCHost::create(evmc_message const& _msg) noexcept +{ + u256 gas = _msg.gas; + u256 value = fromEvmC(_msg.value); + bytesConstRef init = {_msg.input_data, _msg.input_size}; + u256 salt = fromEvmC(_msg.create2_salt); + Instruction opcode = _msg.kind == EVMC_CREATE ? OP_CREATE : OP_CREATE2; + + // ExtVM::create takes the sender address from .myAddress. + assert(fromEvmC(_msg.sender) == m_extVM.myAddress); + + CreateResult result = m_extVM.create(value, gas, init, opcode, salt, {}); + evmc_result evmcResult = {}; + evmcResult.status_code = result.status; + evmcResult.gas_left = static_cast(gas); + + if (result.status == EVMC_SUCCESS) + evmcResult.create_address = toEvmC(result.address); + else + { + // Pass the output to the EVM without a copy. The EVM will delete it + // when finished with it. + + // First assign reference. References are not invalidated when vector + // of bytes is moved. See `.takeBytes()` below. + evmcResult.output_data = result.output.data(); + evmcResult.output_size = result.output.size(); + + // Place a new vector of bytes containing output in result's reserved memory. + auto* data = evmc_get_optional_storage(&evmcResult); + static_assert(sizeof(bytes) <= sizeof(*data), "Vector is too big"); + new (data) bytes(result.output.takeBytes()); + // Set the destructor to delete the vector. + evmcResult.release = [](evmc_result const* _result) { + auto* data = evmc_get_const_optional_storage(_result); + auto& output = reinterpret_cast(*data); + // Explicitly call vector's destructor to release its data. + // This is normal pattern when placement new operator is used. + output.~bytes(); + }; + } + return evmc::Result{evmcResult}; +} + +evmc::Result EvmCHost::call(evmc_message const& _msg) noexcept +{ + assert(_msg.gas >= 0 && "Invalid gas value"); + assert(_msg.depth == static_cast(m_extVM.depth) + 1); + + record_account_access(_msg.recipient); + + // Handle CREATE separately. + if (_msg.kind == EVMC_CREATE || _msg.kind == EVMC_CREATE2) + return create(_msg); + + CallParameters params; + params.gas = _msg.gas; + params.apparentValue = fromEvmC(_msg.value); + params.valueTransfer = _msg.kind == EVMC_DELEGATECALL ? 0 : params.apparentValue; + params.senderAddress = fromEvmC(_msg.sender); + params.codeAddress = fromEvmC(_msg.code_address); + params.receiveAddress = _msg.kind == EVMC_CALL ? params.codeAddress : m_extVM.myAddress; + params.data = {_msg.input_data, _msg.input_size}; + params.staticCall = (_msg.flags & EVMC_STATIC) != 0; + params.onOp = {}; + + CallResult result = m_extVM.call(params); + evmc_result evmcResult = {}; + evmcResult.status_code = result.status; + evmcResult.gas_left = static_cast(params.gas); + + // Pass the output to the EVM without a copy. The EVM will delete it + // when finished with it. + + // First assign reference. References are not invalidated when vector + // of bytes is moved. See `.takeBytes()` below. + evmcResult.output_data = result.output.data(); + evmcResult.output_size = result.output.size(); + + // Place a new vector of bytes containing output in result's reserved memory. + auto* data = evmc_get_optional_storage(&evmcResult); + static_assert(sizeof(bytes) <= sizeof(*data), "Vector is too big"); + new (data) bytes(result.output.takeBytes()); + // Set the destructor to delete the vector. + evmcResult.release = [](evmc_result const* _result) { + auto* data = evmc_get_const_optional_storage(_result); + auto& output = reinterpret_cast(*data); + // Explicitly call vector's destructor to release its data. + // This is normal pattern when placement new operator is used. + output.~bytes(); + }; + return evmc::Result{evmcResult}; +} + +ExtVMFace::ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, + u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, + u256 const& _version, unsigned _depth, bool _isCreate, bool _staticCall) + : m_envInfo(_envInfo), + myAddress(_myAddress), + caller(_caller), + origin(_origin), + value(_value), + gasPrice(_gasPrice), + data(_data), + code(std::move(_code)), + codeHash(_codeHash), + version(_version), + depth(_depth), + isCreate(_isCreate), + staticCall(_staticCall) +{} + +} // namespace eth +} // namespace dev diff --git a/src/eth_client/libevm/ExtVMFace.h b/src/eth_client/libevm/ExtVMFace.h new file mode 100644 index 0000000000..9a7ab4f6f2 --- /dev/null +++ b/src/eth_client/libevm/ExtVMFace.h @@ -0,0 +1,384 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ +/// Reference to a slice of buffer that also owns the buffer. +/// +/// This is extension to the concept C++ STL library names as array_view +/// (also known as gsl::span, array_ref, here vector_ref) -- reference to +/// continuous non-modifiable memory. The extension makes the object also owning +/// the referenced buffer. +/// +/// This type is used by VMs to return output coming from RETURN instruction. +/// To avoid memory copy, a VM returns its whole memory + the information what +/// part of this memory is actually the output. This simplifies the VM design, +/// because there are multiple options how the output will be used (can be +/// ignored, part of it copied, or all of it copied). The decision what to do +/// with it was moved out of VM interface making VMs "stateless". +/// +/// The type is movable, but not copyable. Default constructor available. +using Instruction = uint8_t; +class owning_bytes_ref : public vector_ref +{ +public: + owning_bytes_ref() = default; + + /// @param _bytes The buffer. + /// @param _begin The index of the first referenced byte. + /// @param _size The number of referenced bytes. + owning_bytes_ref(bytes&& _bytes, size_t _begin, size_t _size) : m_bytes(std::move(_bytes)) + { + // Set the reference *after* the buffer is moved to avoid + // pointer invalidation. + retarget(&m_bytes[_begin], _size); + } + + owning_bytes_ref(owning_bytes_ref const&) = delete; + owning_bytes_ref(owning_bytes_ref&&) = default; + owning_bytes_ref& operator=(owning_bytes_ref const&) = delete; + owning_bytes_ref& operator=(owning_bytes_ref&&) = default; + + /// Moves the bytes vector out of here. The object cannot be used any more. + bytes&& takeBytes() + { + reset(); // Reset reference just in case. + return std::move(m_bytes); + } + +private: + bytes m_bytes; +}; + +struct SubState +{ + std::unordered_map> selfdestructs; ///< Any accounts that have selfdestructed. + LogEntries logs; ///< Any logs. + int64_t refunds = 0; ///< Refund counter for storage changes. + + SubState& operator+=(SubState const& _s) + { + for (auto const& i: _s.selfdestructs) + selfdestructs[i.first] += i.second; + refunds += _s.refunds; + logs += _s.logs; + return *this; + } + + void clear() + { + selfdestructs.clear(); + logs.clear(); + refunds = 0; + } +}; + +class ExtVMFace; +class LastBlockHashesFace; +class VMFace; + +using OnOpFunc = std::function; + +struct CallParameters +{ + CallParameters() = default; + CallParameters(Address _senderAddress, Address _codeAddress, Address _receiveAddress, + u256 _valueTransfer, u256 _apparentValue, u256 _gas, bytesConstRef _data, + OnOpFunc _onOpFunc) + : senderAddress(_senderAddress), + codeAddress(_codeAddress), + receiveAddress(_receiveAddress), + valueTransfer(_valueTransfer), + apparentValue(_apparentValue), + gas(_gas), + data(_data), + onOp(_onOpFunc) + {} + Address senderAddress; + Address codeAddress; + Address receiveAddress; + u256 valueTransfer; + u256 apparentValue; + u256 gas; + bytesConstRef data; + bool staticCall = false; + OnOpFunc onOp; +}; + +class EnvInfo +{ +public: + EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed, + u256 const& _chainID) + : m_headerInfo(_current), m_lastHashes(_lh), m_gasUsed(_gasUsed), m_chainID(_chainID) + {} + // Constructor with custom gasLimit - used in some synthetic scenarios like eth_estimateGas RPC + // method + EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed, + u256 const& _gasLimit, u256 const& _chainID) + : EnvInfo(_current, _lh, _gasUsed, _chainID) + { + m_headerInfo.setGasLimit(_gasLimit); + } + + BlockHeader const& header() const { return m_headerInfo; } + + int64_t number() const { return m_headerInfo.number(); } + Address const& author() const { return m_headerInfo.author(); } + int64_t timestamp() const { return m_headerInfo.timestamp(); } + u256 const& difficulty() const { return m_headerInfo.difficulty(); } + u256 const& gasLimit() const { return m_headerInfo.gasLimit(); } + LastBlockHashesFace const& lastHashes() const { return m_lastHashes; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& chainID() const { return m_chainID; } + +private: + BlockHeader m_headerInfo; + LastBlockHashesFace const& m_lastHashes; + u256 m_gasUsed; + u256 m_chainID; +}; + +/// Represents a call result. +/// +/// @todo: Replace with evmc_result in future. +struct CallResult +{ + evmc_status_code status; + owning_bytes_ref output; + + CallResult(evmc_status_code status, owning_bytes_ref&& output) + : status{status}, output{std::move(output)} + {} +}; + +/// Represents a CREATE result. +/// +/// @todo: Replace with evmc_result in future. +struct CreateResult +{ + evmc_status_code status; + owning_bytes_ref output; + h160 address; + + CreateResult(evmc_status_code status, owning_bytes_ref&& output, h160 const& address) + : status{status}, output{std::move(output)}, address{address} + {} +}; + +/** + * @brief Interface and null implementation of the class for specifying VM externalities. + */ +class ExtVMFace +{ +public: + /// Full constructor. + ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, + u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, + u256 const& _version, unsigned _depth, bool _isCreate, bool _staticCall); + + ExtVMFace(ExtVMFace const&) = delete; + ExtVMFace& operator=(ExtVMFace const&) = delete; + + virtual ~ExtVMFace() = default; + + /// Read storage location. + virtual u256 store(u256) { return 0; } + + /// Write a value in storage. + virtual void setStore(u256, u256) {} + + /// Read original storage value (before modifications in the current transaction). + virtual u256 originalStorageValue(u256 const&) { return 0; } + + /// Read address's balance. + virtual u256 balance(Address) { return 0; } + + /// Read address's code. + virtual bytes const& codeAt(Address) { return NullBytes; } + + /// @returns the size of the code in bytes at the given address. + virtual size_t codeSizeAt(Address) { return 0; } + + /// @returns the hash of the code at the given address. + virtual h256 codeHashAt(Address) { return h256{}; } + + /// Does the account exist? + virtual bool exists(Address) { return false; } + + /// Selfdestruct the associated contract and give proceeds to the given address. + /// + /// @param beneficiary The address of the account which will receive ETH + /// from the selfdestructed account. + virtual bool selfdestruct(Address beneficiary) + { + auto& beneficiaries = sub.selfdestructs[myAddress]; + beneficiaries.emplace_back(beneficiary); + return beneficiaries.size() == 1; + } + + /// Create a new (contract) account. + virtual CreateResult create(u256, u256&, bytesConstRef, Instruction, u256, OnOpFunc const&) = 0; + + /// Make a new message call. + virtual CallResult call(CallParameters&) = 0; + + /// Revert any changes made (by any of the other calls). + virtual void log(h256s&& _topics, bytesConstRef _data) + { + sub.logs.push_back(LogEntry(myAddress, std::move(_topics), _data.toBytes())); + } + + /// Hash of a block if within the last 256 blocks, or h256() otherwise. + virtual h256 blockHash(u256 _number) = 0; + + /// Get the execution environment information. + EnvInfo const& envInfo() const { return m_envInfo; } + + /// Return the EVM gas-price schedule for this execution context. + virtual EVMSchedule const& evmSchedule() const { return DefaultSchedule; } + + /// Is the address from precompiled contract + virtual bool isPrecompiled(Address) const = 0; + +private: + EnvInfo const& m_envInfo; + +public: + // TODO: make private + Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be). + Address caller; ///< Address which sent the message (either equal to origin or a contract). + Address origin; ///< Original transactor. + u256 value; ///< Value (in Wei) that was passed to this address. + u256 gasPrice; ///< Price of gas (that we already paid). + bytesConstRef data; ///< Current input data. + bytes code; ///< Current code that is executing. + h256 codeHash; ///< SHA3 hash of the executing code + u256 version; ///< Version of the VM to execute code + u256 salt; ///< Values used in new address construction by CREATE2 + SubState sub; ///< Sub-band VM state (selfdestructs, refund counter, logs). + unsigned depth = 0; ///< Depth of the present call. + bool isCreate = false; ///< Is this a CREATE call? + bool staticCall = false; ///< Throw on state changing. +}; + +/// Extended value for account storage access status. +struct access_value +{ + /// Is the storage key cold or warm. + evmc_access_status access_status{EVMC_ACCESS_COLD}; + + /// Default constructor. + access_value() noexcept = default; + + /// Constructor with initial access status. + access_value(evmc_access_status _access_status) noexcept + : access_status{_access_status} + {} +}; + +/// Access account. +struct AccessAccount +{ + /// Is the account key cold or warm. + evmc_access_status access_status{EVMC_ACCESS_COLD}; + + /// The account storage map. + std::map storage; + + /// Default constructor. + AccessAccount() noexcept = default; +}; + +class EvmCHost : public evmc::Host +{ +public: + explicit EvmCHost(ExtVMFace& _extVM) : m_extVM{_extVM} {} + + bool account_exists(const evmc::address& _addr) const noexcept override; + + evmc::bytes32 get_storage(const evmc::address& _addr, const evmc::bytes32& _key) const + noexcept override; + + evmc_storage_status set_storage(const evmc::address& _addr, const evmc::bytes32& _key, + const evmc::bytes32& _value) noexcept override; + + evmc::uint256be get_balance(const evmc::address& _addr) const noexcept override; + + size_t get_code_size(const evmc::address& _addr) const noexcept override; + + evmc::bytes32 get_code_hash(const evmc::address& _addr) const noexcept override; + + size_t copy_code(const evmc::address& _addr, size_t _codeOffset, uint8_t* _bufferData, + size_t _bufferSize) const noexcept override; + + bool selfdestruct( + const evmc::address& _addr, const evmc::address& _beneficiary) noexcept override; + + evmc::Result call(const evmc_message& _msg) noexcept override; + + evmc_tx_context get_tx_context() const noexcept override; + + evmc::bytes32 get_block_hash(int64_t _blockNumber) const noexcept override; + + void emit_log(const evmc::address& _addr, const uint8_t* _data, size_t _dataSize, + const evmc::bytes32 _topics[], size_t _numTopics) noexcept override; + + evmc_access_status access_account(const evmc::address& addr) noexcept final; + + evmc_access_status access_storage(const evmc::address& addr, + const evmc::bytes32& key) noexcept final; + +private: + evmc::Result create(evmc_message const& _msg) noexcept; + void record_account_access(const evmc::address& addr) const; + +private: + ExtVMFace& m_extVM; + + /// The set of all accounts in the Host, organized by their addresses. + mutable std::map accounts; +}; + +inline evmc::address toEvmC(Address const& _addr) +{ + return reinterpret_cast(_addr); +} + +inline evmc_uint256be toEvmC(h256 const& _h) +{ + return reinterpret_cast(_h); +} + +inline u256 fromEvmC(evmc_uint256be const& _n) +{ + return fromBigEndian(_n.bytes); +} + +inline Address fromEvmC(evmc::address const& _addr) +{ + return reinterpret_cast
(_addr); +} +} // namespace eth +} // namespace dev diff --git a/src/eth_client/libevm/VMFace.h b/src/eth_client/libevm/VMFace.h new file mode 100644 index 0000000000..20efd1f2eb --- /dev/null +++ b/src/eth_client/libevm/VMFace.h @@ -0,0 +1,86 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. +#pragma once + +#include "ExtVMFace.h" +#include +#include + +namespace dev +{ +namespace eth +{ + +struct VMException: Exception {}; +#define ETH_SIMPLE_EXCEPTION_VM(X) struct X: VMException { const char* what() const noexcept override { return #X; } } +ETH_SIMPLE_EXCEPTION_VM(InvalidInstruction); +ETH_SIMPLE_EXCEPTION_VM(BadInstruction); +ETH_SIMPLE_EXCEPTION_VM(BadJumpDestination); +ETH_SIMPLE_EXCEPTION_VM(OutOfGas); +ETH_SIMPLE_EXCEPTION_VM(OutOfStack); +ETH_SIMPLE_EXCEPTION_VM(StackUnderflow); +ETH_SIMPLE_EXCEPTION_VM(DisallowedStateChange); +ETH_SIMPLE_EXCEPTION_VM(BufferOverrun); +ETH_SIMPLE_EXCEPTION_VM(CreateWithValue); +ETH_SIMPLE_EXCEPTION_VM(InvalidCode); + +/// Reports VM internal error. This is not based on VMException because it must be handled +/// differently than defined consensus exceptions. +struct InternalVMError : Exception {}; + +/// Error info for EVMC status code. +using errinfo_evmcStatusCode = boost::error_info; + +struct RevertInstruction: VMException +{ + explicit RevertInstruction(owning_bytes_ref&& _output) : m_output(std::move(_output)) {} + RevertInstruction(RevertInstruction const&) = delete; + RevertInstruction(RevertInstruction&&) = default; + RevertInstruction& operator=(RevertInstruction const&) = delete; + RevertInstruction& operator=(RevertInstruction&&) = default; + + char const* what() const noexcept override { return "Revert instruction"; } + + owning_bytes_ref&& output() { return std::move(m_output); } + +private: + owning_bytes_ref m_output; +}; + + +/// EVM Virtual Machine interface +class VMFace +{ +public: + VMFace() = default; + virtual ~VMFace() = default; + VMFace(VMFace const&) = delete; + VMFace& operator=(VMFace const&) = delete; + + /// VM implementation + virtual owning_bytes_ref exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) = 0; +}; + +/// Helpers: + +// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. +// Currently we just pull out the right (low-order in BE) 160-bits. +inline Address asAddress(u256 _item) +{ + return right160(h256(_item)); +} + +inline u256 fromAddress(Address _a) +{ + return (u160)_a; +} + +// Checks whether address is in the address range for precompiles according to EIP-1352 +inline bool isPrecompiledContract(Address const& _addr) noexcept +{ + static Address const c_maxPrecompiledAddress{0xffff}; + return _addr <= c_maxPrecompiledAddress; +} +} +} diff --git a/src/eth_client/libevm/VMFactory.cpp b/src/eth_client/libevm/VMFactory.cpp new file mode 100644 index 0000000000..1d053c1b63 --- /dev/null +++ b/src/eth_client/libevm/VMFactory.cpp @@ -0,0 +1,138 @@ +// Aleth: Ethereum C++ client, tools and libraries. +// Copyright 2014-2019 Aleth Authors. +// Licensed under the GNU General Public License, Version 3. + +#include "VMFactory.h" +#include "EVMC.h" +#include +#include + +namespace po = boost::program_options; + +namespace dev +{ +namespace eth +{ +namespace +{ + +DEV_SIMPLE_EXCEPTION(VMKindNotSupported); + +auto g_kind = VMKind::Evmone; + +/// The list of EVMC options stored as pairs of (name, value). +std::vector> s_evmcOptions; + +/// A helper type to build the tabled of VM implementations. +/// +/// More readable than std::tuple. +/// Fields are not initialized to allow usage of construction with initializer lists {}. +struct VMKindTableEntry +{ + VMKind kind; + const char* name; +}; + +/// The table of available VM implementations. +/// +/// We don't use a map to avoid complex dynamic initialization. This list will never be long, +/// so linear search only to parse command line arguments is not a problem. +VMKindTableEntry vmKindsTable[] = { + {VMKind::Evmone, "evmone"}, +}; + +void setVMKind(const std::string& _name) +{ + for (auto& entry : vmKindsTable) + { + // Try to find a match in the table of VMs. + if (_name == entry.name) + { + g_kind = entry.kind; + return; + } + } + + BOOST_THROW_EXCEPTION(VMKindNotSupported() << errinfo_comment("VM " + _name + "not supported")); +} +} // namespace + +namespace +{ +/// The name of the program option --evmc. The boost will trim the tailing +/// space and we can reuse this variable in exception message. +const char c_evmcPrefix[] = "evmc "; + +/// The additional parser for EVMC options. The options should look like +/// `--evmc name=value` or `--evmc=name=value`. The boost pass the strings +/// of `name=value` here. This function splits the name and value or reports +/// the syntax error if the `=` character is missing. +void parseEvmcOptions(const std::vector& _opts) +{ + for (auto& s : _opts) + { + auto separatorPos = s.find('='); + if (separatorPos == s.npos) + throw po::invalid_syntax{po::invalid_syntax::missing_parameter, c_evmcPrefix + s}; + auto name = s.substr(0, separatorPos); + auto value = s.substr(separatorPos + 1); + s_evmcOptions.emplace_back(std::move(name), std::move(value)); + } +} +} // namespace + +po::options_description vmProgramOptions(unsigned _lineLength) +{ + // It must be a static object because boost expects const char*. + static const std::string description = [] { + std::string names; + for (auto& entry : vmKindsTable) + { + if (!names.empty()) + names += ", "; + names += entry.name; + } + + return "Select VM implementation. Available options are: " + names + "."; + }(); + + po::options_description opts("VM OPTIONS", _lineLength); + auto add = opts.add_options(); + + add("vm", + po::value() + ->value_name("|") + ->default_value("evmone") + ->notifier(setVMKind), + description.data()); + + add(c_evmcPrefix, + po::value>() + ->multitoken() + ->value_name("