mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 05:36:46 +00:00
Merge branch 'develop' into bzz
This commit is contained in:
commit
a77e704b4a
64 changed files with 4213 additions and 1287 deletions
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
|
|
@ -22,8 +22,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/ethereum/ethash",
|
"ImportPath": "github.com/ethereum/ethash",
|
||||||
"Comment": "v23.1-33-g6ecb8e6",
|
"Comment": "v23.1-73-g67a0e12",
|
||||||
"Rev": "6ecb8e610d60240187b44f61e66b06198c26fae6"
|
"Rev": "67a0e12a091de035ef083186247e84be2d863c62"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/ethereum/serpent-go",
|
"ImportPath": "github.com/ethereum/serpent-go",
|
||||||
|
|
|
||||||
14
Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml
generated
vendored
14
Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml
generated
vendored
|
|
@ -1,6 +1,14 @@
|
||||||
|
# making our travis.yml play well with C++11 by obtaining g++4.8
|
||||||
|
# Taken from this file:
|
||||||
|
# https://github.com/beark/ftl/blob/master/.travis.yml
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get update -qq
|
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||||
- sudo apt-get install -qq wget cmake gcc bash libboost-test-dev nodejs python-pip python-dev
|
- sudo apt-get update -y -qq
|
||||||
- sudo pip install virtualenv -q
|
|
||||||
|
|
||||||
|
install:
|
||||||
|
- sudo apt-get install -qq --yes --force-yes g++-4.8
|
||||||
|
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
|
||||||
|
# need to explicitly request version 1.48 since by default we get 1.46 which does not work with C++11
|
||||||
|
- sudo apt-get install -qq wget cmake bash libboost-test1.48-dev libboost-system1.48-dev libboost-filesystem1.48-dev nodejs python-pip python-dev
|
||||||
|
- sudo pip install virtualenv -q
|
||||||
script: "./test/test.sh"
|
script: "./test/test.sh"
|
||||||
|
|
|
||||||
2
Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt
generated
vendored
2
Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt
generated
vendored
|
|
@ -18,4 +18,4 @@ if (OpenCL_FOUND)
|
||||||
add_subdirectory(src/libethash-cl)
|
add_subdirectory(src/libethash-cl)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
|
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(test/c EXCLUDE_FROM_ALL)
|
add_subdirectory(test/c)
|
||||||
|
|
|
||||||
17
Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
generated
vendored
17
Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
generated
vendored
|
|
@ -85,7 +85,7 @@ func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) (*Params
|
||||||
Epoch: blockNum / epochLength,
|
Epoch: blockNum / epochLength,
|
||||||
}
|
}
|
||||||
C.ethash_params_init(paramsAndCache.params, C.uint32_t(uint32(blockNum)))
|
C.ethash_params_init(paramsAndCache.params, C.uint32_t(uint32(blockNum)))
|
||||||
paramsAndCache.cache.mem = C.malloc(paramsAndCache.params.cache_size)
|
paramsAndCache.cache.mem = C.malloc(C.size_t(paramsAndCache.params.cache_size))
|
||||||
|
|
||||||
seedHash, err := GetSeedHash(blockNum)
|
seedHash, err := GetSeedHash(blockNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -100,14 +100,14 @@ func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) (*Params
|
||||||
return paramsAndCache, nil
|
return paramsAndCache, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pow *Ethash) UpdateCache(force bool) error {
|
func (pow *Ethash) UpdateCache(blockNum uint64, force bool) error {
|
||||||
pow.cacheMutex.Lock()
|
pow.cacheMutex.Lock()
|
||||||
defer pow.cacheMutex.Unlock()
|
defer pow.cacheMutex.Unlock()
|
||||||
|
|
||||||
thisEpoch := pow.chainManager.CurrentBlock().NumberU64() / epochLength
|
thisEpoch := blockNum / epochLength
|
||||||
if force || pow.paramsAndCache.Epoch != thisEpoch {
|
if force || pow.paramsAndCache.Epoch != thisEpoch {
|
||||||
var err error
|
var err error
|
||||||
pow.paramsAndCache, err = makeParamsAndCache(pow.chainManager, pow.chainManager.CurrentBlock().NumberU64())
|
pow.paramsAndCache, err = makeParamsAndCache(pow.chainManager, blockNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +118,7 @@ func (pow *Ethash) UpdateCache(force bool) error {
|
||||||
|
|
||||||
func makeDAG(p *ParamsAndCache) *DAG {
|
func makeDAG(p *ParamsAndCache) *DAG {
|
||||||
d := &DAG{
|
d := &DAG{
|
||||||
dag: C.malloc(p.params.full_size),
|
dag: C.malloc(C.size_t(p.params.full_size)),
|
||||||
file: false,
|
file: false,
|
||||||
paramsAndCache: p,
|
paramsAndCache: p,
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +326,6 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stop:
|
case <-stop:
|
||||||
powlogger.Infoln("Breaking from mining")
|
|
||||||
pow.HashRate = 0
|
pow.HashRate = 0
|
||||||
return 0, nil, nil
|
return 0, nil, nil
|
||||||
default:
|
default:
|
||||||
|
|
@ -386,13 +385,13 @@ func (pow *Ethash) verify(hash common.Hash, mixDigest common.Hash, difficulty *b
|
||||||
if blockNum/epochLength < pow.paramsAndCache.Epoch {
|
if blockNum/epochLength < pow.paramsAndCache.Epoch {
|
||||||
var err error
|
var err error
|
||||||
// If we can't make the params for some reason, this block is invalid
|
// If we can't make the params for some reason, this block is invalid
|
||||||
pAc, err = makeParamsAndCache(pow.chainManager, blockNum)
|
pAc, err = makeParamsAndCache(pow.chainManager, blockNum+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
powlogger.Infoln(err)
|
powlogger.Infoln("big fucking eror", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pow.UpdateCache(false)
|
pow.UpdateCache(blockNum, false)
|
||||||
pow.cacheMutex.RLock()
|
pow.cacheMutex.RLock()
|
||||||
defer pow.cacheMutex.RUnlock()
|
defer pow.cacheMutex.RUnlock()
|
||||||
pAc = pow.paramsAndCache
|
pAc = pow.paramsAndCache
|
||||||
|
|
|
||||||
5
Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt
generated
vendored
5
Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt
generated
vendored
|
|
@ -6,6 +6,11 @@ if (MSVC)
|
||||||
add_definitions("/openmp")
|
add_definitions("/openmp")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# enable C++11, should probably be a bit more specific about compiler
|
||||||
|
if (NOT MSVC)
|
||||||
|
SET(CMAKE_CXX_FLAGS "-std=c++11")
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT MPI_FOUND)
|
if (NOT MPI_FOUND)
|
||||||
find_package(MPI)
|
find_package(MPI)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
60
Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp
generated
vendored
60
Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp
generated
vendored
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <chrono>
|
||||||
#include <libethash/ethash.h>
|
#include <libethash/ethash.h>
|
||||||
#include <libethash/util.h>
|
#include <libethash/util.h>
|
||||||
#ifdef OPENCL
|
#ifdef OPENCL
|
||||||
|
|
@ -41,6 +41,8 @@
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
|
||||||
|
using std::chrono::high_resolution_clock;
|
||||||
|
|
||||||
#if defined(OPENCL)
|
#if defined(OPENCL)
|
||||||
const unsigned trials = 1024*1024*32;
|
const unsigned trials = 1024*1024*32;
|
||||||
#elif defined(FULL)
|
#elif defined(FULL)
|
||||||
|
|
@ -122,50 +124,50 @@ extern "C" int main(void)
|
||||||
|
|
||||||
// compute cache or full data
|
// compute cache or full data
|
||||||
{
|
{
|
||||||
clock_t startTime = clock();
|
auto startTime = high_resolution_clock::now();
|
||||||
ethash_mkcache(&cache, ¶ms, seed);
|
ethash_mkcache(&cache, ¶ms, seed);
|
||||||
clock_t time = clock() - startTime;
|
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||||
|
|
||||||
uint8_t cache_hash[32];
|
uint8_t cache_hash[32];
|
||||||
SHA3_256(cache_hash, (uint8_t const*)cache_mem, params.cache_size);
|
SHA3_256(cache_hash, (uint8_t const*)cache_mem, params.cache_size);
|
||||||
debugf("ethash_mkcache: %ums, sha3: %s\n", (unsigned)((time*1000)/CLOCKS_PER_SEC), bytesToHexString(cache_hash,sizeof(cache_hash)).data());
|
debugf("ethash_mkcache: %ums, sha3: %s\n", (unsigned)time, bytesToHexString(cache_hash,sizeof(cache_hash)).data());
|
||||||
|
|
||||||
// print a couple of test hashes
|
// print a couple of test hashes
|
||||||
{
|
{
|
||||||
const clock_t startTime = clock();
|
auto startTime = high_resolution_clock::now();
|
||||||
ethash_return_value hash;
|
ethash_return_value hash;
|
||||||
ethash_light(&hash, &cache, ¶ms, previous_hash, 0);
|
ethash_light(&hash, &cache, ¶ms, previous_hash, 0);
|
||||||
const clock_t time = clock() - startTime;
|
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||||
debugf("ethash_light test: %ums, %s\n", (unsigned)((time*1000)/CLOCKS_PER_SEC), bytesToHexString(hash.result, 32).data());
|
debugf("ethash_light test: %ums, %s\n", (unsigned)time, bytesToHexString(hash.result, 32).data());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FULL
|
#ifdef FULL
|
||||||
startTime = clock();
|
startTime = high_resolution_clock::now();
|
||||||
ethash_compute_full_data(full_mem, ¶ms, &cache);
|
ethash_compute_full_data(full_mem, ¶ms, &cache);
|
||||||
time = clock() - startTime;
|
time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||||
debugf("ethash_compute_full_data: %ums\n", (unsigned)((time*1000)/CLOCKS_PER_SEC));
|
debugf("ethash_compute_full_data: %ums\n", (unsigned)time);
|
||||||
#endif // FULL
|
#endif // FULL
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OPENCL
|
#ifdef OPENCL
|
||||||
ethash_cl_miner miner;
|
ethash_cl_miner miner;
|
||||||
{
|
{
|
||||||
const clock_t startTime = clock();
|
auto startTime = high_resolution_clock::now();
|
||||||
if (!miner.init(params, seed))
|
if (!miner.init(params, seed))
|
||||||
exit(-1);
|
exit(-1);
|
||||||
const clock_t time = clock() - startTime;
|
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||||
debugf("ethash_cl_miner init: %ums\n", (unsigned)((time*1000)/CLOCKS_PER_SEC));
|
debugf("ethash_cl_miner init: %ums\n", (unsigned)time);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef FULL
|
#ifdef FULL
|
||||||
{
|
{
|
||||||
const clock_t startTime = clock();
|
auto startTime = high_resolution_clock::now();
|
||||||
ethash_return_value hash;
|
ethash_return_value hash;
|
||||||
ethash_full(&hash, full_mem, ¶ms, previous_hash, 0);
|
ethash_full(&hash, full_mem, ¶ms, previous_hash, 0);
|
||||||
const clock_t time = clock() - startTime;
|
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||||
debugf("ethash_full test: %uns, %s\n", (unsigned)((time*1000000)/CLOCKS_PER_SEC), bytesToHexString(hash.result, 32).data());
|
debugf("ethash_full test: %uns, %s\n", (unsigned)time);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -186,10 +188,12 @@ extern "C" int main(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure nothing else is going on
|
||||||
|
miner.finish();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
auto startTime = high_resolution_clock::now();
|
||||||
clock_t startTime = clock();
|
|
||||||
unsigned hash_count = trials;
|
unsigned hash_count = trials;
|
||||||
|
|
||||||
#ifdef OPENCL
|
#ifdef OPENCL
|
||||||
|
|
@ -201,7 +205,7 @@ extern "C" int main(void)
|
||||||
|
|
||||||
virtual bool found(uint64_t const* nonces, uint32_t count)
|
virtual bool found(uint64_t const* nonces, uint32_t count)
|
||||||
{
|
{
|
||||||
nonce_vec.assign(nonces, nonces + count);
|
nonce_vec.insert(nonce_vec.end(), nonces, nonces + count);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,15 +245,23 @@ extern "C" int main(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
auto time = std::chrono::duration_cast<std::chrono::microseconds>(high_resolution_clock::now() - startTime).count();
|
||||||
clock_t time = std::max((clock_t)1u, clock() - startTime);
|
debugf("Search took: %ums\n", (unsigned)time/1000);
|
||||||
|
|
||||||
unsigned read_size = ACCESSES * MIX_BYTES;
|
unsigned read_size = ACCESSES * MIX_BYTES;
|
||||||
|
#if defined(OPENCL) || defined(FULL)
|
||||||
debugf(
|
debugf(
|
||||||
"hashrate: %8u, bw: %6u MB/s\n",
|
"hashrate: %8.2f Mh/s, bw: %8.2f GB/s\n",
|
||||||
(unsigned)(((uint64_t)hash_count*CLOCKS_PER_SEC)/time),
|
(double)hash_count * (1000*1000)/time / (1000*1000),
|
||||||
(unsigned)((((uint64_t)hash_count*read_size*CLOCKS_PER_SEC)/time) / (1024*1024))
|
(double)hash_count*read_size * (1000*1000)/time / (1024*1024*1024)
|
||||||
);
|
);
|
||||||
|
#else
|
||||||
|
debugf(
|
||||||
|
"hashrate: %8.2f Kh/s, bw: %8.2f MB/s\n",
|
||||||
|
(double)hash_count * (1000*1000)/time / (1000),
|
||||||
|
(double)hash_count*read_size * (1000*1000)/time / (1024*1024)
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
free(cache_mem_buf);
|
free(cache_mem_buf);
|
||||||
#ifdef FULL
|
#ifdef FULL
|
||||||
|
|
|
||||||
7
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/CMakeLists.txt
generated
vendored
7
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/CMakeLists.txt
generated
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
set(LIBRARY ethash-cl)
|
set(LIBRARY ethash-cl)
|
||||||
set(CMAKE_BUILD_TYPE Release)
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
|
||||||
|
|
@ -28,11 +30,16 @@ if (NOT MSVC)
|
||||||
endif ()
|
endif ()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(OpenCL_FOUND TRUE)
|
||||||
|
set(OpenCL_INCLUDE_DIRS /usr/include/CL)
|
||||||
|
set(OpenCL_LIBRARIES -lOpenCL)
|
||||||
|
|
||||||
if (NOT OpenCL_FOUND)
|
if (NOT OpenCL_FOUND)
|
||||||
find_package(OpenCL)
|
find_package(OpenCL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (OpenCL_FOUND)
|
if (OpenCL_FOUND)
|
||||||
|
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -pedantic -fPIC ${CMAKE_CXX_FLAGS}")
|
||||||
include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
include_directories(..)
|
include_directories(..)
|
||||||
add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp)
|
add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp)
|
||||||
|
|
|
||||||
16
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.cpp
generated
vendored
16
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.cpp
generated
vendored
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -52,6 +54,14 @@ ethash_cl_miner::ethash_cl_miner()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ethash_cl_miner::finish()
|
||||||
|
{
|
||||||
|
if (m_queue())
|
||||||
|
{
|
||||||
|
m_queue.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size)
|
bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size)
|
||||||
{
|
{
|
||||||
// store params
|
// store params
|
||||||
|
|
@ -95,7 +105,7 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32],
|
||||||
}
|
}
|
||||||
|
|
||||||
// create context
|
// create context
|
||||||
m_context = cl::Context(std::vector<cl::Device>(&device, &device+1));
|
m_context = cl::Context(std::vector<cl::Device>(&device, &device + 1));
|
||||||
m_queue = cl::CommandQueue(m_context, device);
|
m_queue = cl::CommandQueue(m_context, device);
|
||||||
|
|
||||||
// use requested workgroup size, but we require multiple of 8
|
// use requested workgroup size, but we require multiple of 8
|
||||||
|
|
@ -308,6 +318,10 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
|
||||||
if (exit)
|
if (exit)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// reset search buffer if we're still going
|
||||||
|
if (num_found)
|
||||||
|
m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero);
|
||||||
|
|
||||||
pending.pop();
|
pending.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.h
generated
vendored
1
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.h
generated
vendored
|
|
@ -21,6 +21,7 @@ public:
|
||||||
|
|
||||||
bool init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size = 64);
|
bool init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size = 64);
|
||||||
|
|
||||||
|
void finish();
|
||||||
void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count);
|
void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count);
|
||||||
void search(uint8_t const* header, uint64_t target, search_hook& hook);
|
void search(uint8_t const* header, uint64_t target, search_hook& hook);
|
||||||
|
|
||||||
|
|
|
||||||
7
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt
generated
vendored
7
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt
generated
vendored
|
|
@ -12,6 +12,7 @@ endif()
|
||||||
|
|
||||||
set(FILES util.c
|
set(FILES util.c
|
||||||
util.h
|
util.h
|
||||||
|
io.c
|
||||||
internal.c
|
internal.c
|
||||||
ethash.h
|
ethash.h
|
||||||
endian.h
|
endian.h
|
||||||
|
|
@ -19,6 +20,12 @@ set(FILES util.c
|
||||||
fnv.h
|
fnv.h
|
||||||
data_sizes.h)
|
data_sizes.h)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
list(APPEND FILES io_win32.c)
|
||||||
|
else()
|
||||||
|
list(APPEND FILES io_posix.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT CRYPTOPP_FOUND)
|
if (NOT CRYPTOPP_FOUND)
|
||||||
find_package(CryptoPP 5.6.2)
|
find_package(CryptoPP 5.6.2)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
4
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h
generated
vendored
4
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h
generated
vendored
|
|
@ -48,7 +48,7 @@ extern "C" {
|
||||||
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
|
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
|
||||||
|
|
||||||
|
|
||||||
static const size_t dag_sizes[2048] = {
|
static const uint64_t dag_sizes[2048] = {
|
||||||
1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U,
|
1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U,
|
||||||
1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U,
|
1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U,
|
||||||
1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U,
|
1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U,
|
||||||
|
|
@ -477,7 +477,7 @@ static const size_t dag_sizes[2048] = {
|
||||||
// While[! PrimeQ[i], i--];
|
// While[! PrimeQ[i], i--];
|
||||||
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
|
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
|
||||||
|
|
||||||
const size_t cache_sizes[2048] = {
|
const uint64_t cache_sizes[2048] = {
|
||||||
16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U,
|
16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U,
|
||||||
17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U,
|
17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U,
|
||||||
18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U,
|
18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U,
|
||||||
|
|
|
||||||
33
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h
generated
vendored
33
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h
generated
vendored
|
|
@ -43,8 +43,8 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct ethash_params {
|
typedef struct ethash_params {
|
||||||
size_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
|
uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
|
||||||
size_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
|
uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
|
||||||
} ethash_params;
|
} ethash_params;
|
||||||
|
|
||||||
typedef struct ethash_return_value {
|
typedef struct ethash_return_value {
|
||||||
|
|
@ -52,8 +52,8 @@ typedef struct ethash_return_value {
|
||||||
uint8_t mix_hash[32];
|
uint8_t mix_hash[32];
|
||||||
} ethash_return_value;
|
} ethash_return_value;
|
||||||
|
|
||||||
size_t ethash_get_datasize(const uint32_t block_number);
|
uint64_t ethash_get_datasize(const uint32_t block_number);
|
||||||
size_t ethash_get_cachesize(const uint32_t block_number);
|
uint64_t ethash_get_cachesize(const uint32_t block_number);
|
||||||
|
|
||||||
// initialize the parameters
|
// initialize the parameters
|
||||||
static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
|
static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
|
||||||
|
|
@ -93,23 +93,30 @@ static inline void ethash_compute_full(ethash_return_value *ret, void const *ful
|
||||||
ethash_full(ret, full, params, header_hash, nonce);
|
ethash_full(ret, full, params, header_hash, nonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns if hash is less than or equal to difficulty
|
/// @brief Compare two s256-bit big-endian values.
|
||||||
static inline int ethash_check_difficulty(
|
/// @returns 1 if @a a is less than or equal to @a b, 0 otherwise.
|
||||||
const uint8_t hash[32],
|
/// Both parameters are 256-bit big-endian values.
|
||||||
const uint8_t difficulty[32]) {
|
static inline int ethash_leq_be256(const uint8_t a[32], const uint8_t b[32]) {
|
||||||
// Difficulty is big endian
|
// Boundary is big endian
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
if (hash[i] == difficulty[i]) continue;
|
if (a[i] == b[i])
|
||||||
return hash[i] < difficulty[i];
|
continue;
|
||||||
|
return a[i] < b[i];
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ethash_quick_check_difficulty(
|
/// Perofrms a cursory check on the validity of the nonce.
|
||||||
|
/// @returns 1 if the nonce may possibly be valid for the given header_hash & boundary.
|
||||||
|
/// @p boundary equivalent to 2 ^ 256 / block_difficulty, represented as a 256-bit big-endian.
|
||||||
|
int ethash_preliminary_check_boundary(
|
||||||
const uint8_t header_hash[32],
|
const uint8_t header_hash[32],
|
||||||
const uint64_t nonce,
|
const uint64_t nonce,
|
||||||
const uint8_t mix_hash[32],
|
const uint8_t mix_hash[32],
|
||||||
const uint8_t difficulty[32]);
|
const uint8_t boundary[32]);
|
||||||
|
|
||||||
|
#define ethash_quick_check_difficulty ethash_preliminary_check_boundary
|
||||||
|
#define ethash_check_difficulty ethash_leq_be256
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c
generated
vendored
8
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c
generated
vendored
|
|
@ -37,12 +37,12 @@
|
||||||
#include "sha3.h"
|
#include "sha3.h"
|
||||||
#endif // WITH_CRYPTOPP
|
#endif // WITH_CRYPTOPP
|
||||||
|
|
||||||
size_t ethash_get_datasize(const uint32_t block_number) {
|
uint64_t ethash_get_datasize(const uint32_t block_number) {
|
||||||
assert(block_number / EPOCH_LENGTH < 2048);
|
assert(block_number / EPOCH_LENGTH < 2048);
|
||||||
return dag_sizes[block_number / EPOCH_LENGTH];
|
return dag_sizes[block_number / EPOCH_LENGTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ethash_get_cachesize(const uint32_t block_number) {
|
uint64_t ethash_get_cachesize(const uint32_t block_number) {
|
||||||
assert(block_number / EPOCH_LENGTH < 2048);
|
assert(block_number / EPOCH_LENGTH < 2048);
|
||||||
return cache_sizes[block_number / EPOCH_LENGTH];
|
return cache_sizes[block_number / EPOCH_LENGTH];
|
||||||
}
|
}
|
||||||
|
|
@ -280,7 +280,7 @@ void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) {
|
||||||
SHA3_256(seedhash, seedhash, 32);
|
SHA3_256(seedhash, seedhash, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ethash_quick_check_difficulty(
|
int ethash_preliminary_check_boundary(
|
||||||
const uint8_t header_hash[32],
|
const uint8_t header_hash[32],
|
||||||
const uint64_t nonce,
|
const uint64_t nonce,
|
||||||
const uint8_t mix_hash[32],
|
const uint8_t mix_hash[32],
|
||||||
|
|
@ -288,7 +288,7 @@ int ethash_quick_check_difficulty(
|
||||||
|
|
||||||
uint8_t return_hash[32];
|
uint8_t return_hash[32];
|
||||||
ethash_quick_hash(return_hash, header_hash, nonce, mix_hash);
|
ethash_quick_hash(return_hash, header_hash, nonce, mix_hash);
|
||||||
return ethash_check_difficulty(return_hash, difficulty);
|
return ethash_leq_be256(return_hash, difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
|
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
|
||||||
|
|
|
||||||
89
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.c
generated
vendored
Normal file
89
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.c
generated
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethash.
|
||||||
|
|
||||||
|
ethash 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.
|
||||||
|
|
||||||
|
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file io.c
|
||||||
|
* @author Lefteris Karapetsas <lefteris@ethdev.com>
|
||||||
|
* @date 2015
|
||||||
|
*/
|
||||||
|
#include "io.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// silly macro to save some typing
|
||||||
|
#define PASS_ARR(c_) (c_), sizeof(c_)
|
||||||
|
|
||||||
|
static bool ethash_io_write_file(char const *dirname,
|
||||||
|
char const* filename,
|
||||||
|
size_t filename_length,
|
||||||
|
void const* data,
|
||||||
|
size_t data_size)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
char *fullname = ethash_io_create_filename(dirname, filename, filename_length);
|
||||||
|
if (!fullname) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FILE *f = fopen(fullname, "wb");
|
||||||
|
if (!f) {
|
||||||
|
goto free_name;
|
||||||
|
}
|
||||||
|
if (data_size != fwrite(data, 1, data_size, f)) {
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
close:
|
||||||
|
fclose(f);
|
||||||
|
free_name:
|
||||||
|
free(fullname);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ethash_io_write(char const *dirname,
|
||||||
|
ethash_params const* params,
|
||||||
|
ethash_blockhash_t seedhash,
|
||||||
|
void const* cache,
|
||||||
|
uint8_t **data,
|
||||||
|
uint64_t *data_size)
|
||||||
|
{
|
||||||
|
char info_buffer[DAG_MEMO_BYTESIZE];
|
||||||
|
// allocate the bytes
|
||||||
|
uint8_t *temp_data_ptr = malloc((size_t)params->full_size);
|
||||||
|
if (!temp_data_ptr) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
ethash_compute_full_data(temp_data_ptr, params, cache);
|
||||||
|
|
||||||
|
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, (size_t)params->full_size)) {
|
||||||
|
goto fail_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
ethash_io_serialize_info(REVISION, seedhash, info_buffer);
|
||||||
|
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) {
|
||||||
|
goto fail_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = temp_data_ptr;
|
||||||
|
*data_size = params->full_size;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail_free:
|
||||||
|
free(temp_data_ptr);
|
||||||
|
end:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef PASS_ARR
|
||||||
116
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.h
generated
vendored
Normal file
116
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io.h
generated
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethash.
|
||||||
|
|
||||||
|
ethash 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.
|
||||||
|
|
||||||
|
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file io.h
|
||||||
|
* @author Lefteris Karapetsas <lefteris@ethdev.com>
|
||||||
|
* @date 2015
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "ethash.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct ethash_blockhash { uint8_t b[32]; } ethash_blockhash_t;
|
||||||
|
|
||||||
|
static const char DAG_FILE_NAME[] = "full";
|
||||||
|
static const char DAG_MEMO_NAME[] = "full.info";
|
||||||
|
// MSVC thinks that "static const unsigned int" is not a compile time variable. Sorry for the #define :(
|
||||||
|
#define DAG_MEMO_BYTESIZE 36
|
||||||
|
|
||||||
|
/// Possible return values of @see ethash_io_prepare
|
||||||
|
enum ethash_io_rc {
|
||||||
|
ETHASH_IO_FAIL = 0, ///< There has been an IO failure
|
||||||
|
ETHASH_IO_MEMO_MISMATCH, ///< Memo file either did not exist or there was content mismatch
|
||||||
|
ETHASH_IO_MEMO_MATCH, ///< Memo file existed and contents matched. No need to do anything
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares io for ethash
|
||||||
|
*
|
||||||
|
* Create the DAG directory if it does not exist, and check if the memo file matches.
|
||||||
|
* If it does not match then it's deleted to pave the way for @ref ethash_io_write()
|
||||||
|
*
|
||||||
|
* @param dirname A null terminated c-string of the path of the ethash
|
||||||
|
* data directory. If it does not exist it's created.
|
||||||
|
* @param seedhash The seedhash of the current block number
|
||||||
|
* @return For possible return values @see enum ethash_io_rc
|
||||||
|
*/
|
||||||
|
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash);
|
||||||
|
/**
|
||||||
|
* Fully computes data and writes it to the file on disk.
|
||||||
|
*
|
||||||
|
* This function should be called after @see ethash_io_prepare() and only if
|
||||||
|
* its return value is @c ETHASH_IO_MEMO_MISMATCH. Will write both the full data
|
||||||
|
* and the memo file.
|
||||||
|
*
|
||||||
|
* @param[in] dirname A null terminated c-string of the path of the ethash
|
||||||
|
* data directory. Has to exist.
|
||||||
|
* @param[in] params An ethash_params object containing the full size
|
||||||
|
* and the cache size
|
||||||
|
* @param[in] seedhash The seedhash of the current block number
|
||||||
|
* @param[in] cache The cache data. Would have usually been calulated by
|
||||||
|
* @see ethash_prep_light().
|
||||||
|
* @param[out] data Pass a pointer to uint8_t by reference here. If the
|
||||||
|
* function is succesfull then this point to the allocated
|
||||||
|
* data calculated by @see ethash_prep_full(). Memory
|
||||||
|
* ownership is transfered to the callee. Remember that
|
||||||
|
* you eventually need to free this with a call to free().
|
||||||
|
* @param[out] data_size Pass a uint64_t by value. If the function is succesfull
|
||||||
|
* then this will contain the number of bytes allocated
|
||||||
|
* for @a data.
|
||||||
|
* @return True for success and false in case of failure.
|
||||||
|
*/
|
||||||
|
bool ethash_io_write(char const *dirname,
|
||||||
|
ethash_params const* params,
|
||||||
|
ethash_blockhash_t seedhash,
|
||||||
|
void const* cache,
|
||||||
|
uint8_t **data,
|
||||||
|
uint64_t *data_size);
|
||||||
|
|
||||||
|
static inline void ethash_io_serialize_info(uint32_t revision,
|
||||||
|
ethash_blockhash_t seed_hash,
|
||||||
|
char *output)
|
||||||
|
{
|
||||||
|
// if .info is only consumed locally we don't really care about endianess
|
||||||
|
memcpy(output, &revision, 4);
|
||||||
|
memcpy(output + 4, &seed_hash, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char *ethash_io_create_filename(char const *dirname,
|
||||||
|
char const* filename,
|
||||||
|
size_t filename_length)
|
||||||
|
{
|
||||||
|
// in C the cast is not needed, but a C++ compiler will complain for invalid conversion
|
||||||
|
char *name = (char*)malloc(strlen(dirname) + filename_length);
|
||||||
|
if (!name) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
name[0] = '\0';
|
||||||
|
strcat(name, dirname);
|
||||||
|
strcat(name, filename);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
76
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_posix.c
generated
vendored
Normal file
76
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_posix.c
generated
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethash.
|
||||||
|
|
||||||
|
ethash 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.
|
||||||
|
|
||||||
|
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file io_posix.c
|
||||||
|
* @author Lefteris Karapetsas <lefteris@ethdev.com>
|
||||||
|
* @date 2015
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash)
|
||||||
|
{
|
||||||
|
char read_buffer[DAG_MEMO_BYTESIZE];
|
||||||
|
char expect_buffer[DAG_MEMO_BYTESIZE];
|
||||||
|
enum ethash_io_rc ret = ETHASH_IO_FAIL;
|
||||||
|
|
||||||
|
// assert directory exists, full owner permissions and read/search for others
|
||||||
|
int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||||
|
if (rc == -1 && errno != EEXIST) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME));
|
||||||
|
if (!memofile) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to open memo file
|
||||||
|
FILE *f = fopen(memofile, "rb");
|
||||||
|
if (!f) {
|
||||||
|
// file does not exist, so no checking happens. All is fine.
|
||||||
|
ret = ETHASH_IO_MEMO_MISMATCH;
|
||||||
|
goto free_memo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) {
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
ethash_io_serialize_info(REVISION, seedhash, expect_buffer);
|
||||||
|
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) {
|
||||||
|
// we have different memo contents so delete the memo file
|
||||||
|
if (unlink(memofile) != 0) {
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
ret = ETHASH_IO_MEMO_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ETHASH_IO_MEMO_MATCH;
|
||||||
|
|
||||||
|
close:
|
||||||
|
fclose(f);
|
||||||
|
free_memo:
|
||||||
|
free(memofile);
|
||||||
|
end:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
73
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_win32.c
generated
vendored
Normal file
73
Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/io_win32.c
generated
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethash.
|
||||||
|
|
||||||
|
ethash 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.
|
||||||
|
|
||||||
|
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file io_win32.c
|
||||||
|
* @author Lefteris Karapetsas <lefteris@ethdev.com>
|
||||||
|
* @date 2015
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include <direct.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seedhash)
|
||||||
|
{
|
||||||
|
char read_buffer[DAG_MEMO_BYTESIZE];
|
||||||
|
char expect_buffer[DAG_MEMO_BYTESIZE];
|
||||||
|
enum ethash_io_rc ret = ETHASH_IO_FAIL;
|
||||||
|
|
||||||
|
// assert directory exists
|
||||||
|
int rc = _mkdir(dirname);
|
||||||
|
if (rc == -1 && errno != EEXIST) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME));
|
||||||
|
if (!memofile) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to open memo file
|
||||||
|
FILE *f = fopen(memofile, "rb");
|
||||||
|
if (!f) {
|
||||||
|
// file does not exist, so no checking happens. All is fine.
|
||||||
|
ret = ETHASH_IO_MEMO_MISMATCH;
|
||||||
|
goto free_memo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) {
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
ethash_io_serialize_info(REVISION, seedhash, expect_buffer);
|
||||||
|
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) {
|
||||||
|
// we have different memo contents so delete the memo file
|
||||||
|
if (_unlink(memofile) != 0) {
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
ret = ETHASH_IO_MEMO_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ETHASH_IO_MEMO_MATCH;
|
||||||
|
|
||||||
|
close:
|
||||||
|
fclose(f);
|
||||||
|
free_memo:
|
||||||
|
free(memofile);
|
||||||
|
end:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
57
Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c
generated
vendored
57
Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c
generated
vendored
|
|
@ -5,6 +5,14 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "../libethash/ethash.h"
|
#include "../libethash/ethash.h"
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
#define PY_STRING_FORMAT "y#"
|
||||||
|
#define PY_CONST_STRING_FORMAT "y"
|
||||||
|
#else
|
||||||
|
#define PY_STRING_FORMAT "s#"
|
||||||
|
#define PY_CONST_STRING_FORMAT "s"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MIX_WORDS (MIX_BYTES/4)
|
#define MIX_WORDS (MIX_BYTES/4)
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
@ -46,7 +54,7 @@ mkcache_bytes(PyObject *self, PyObject *args) {
|
||||||
unsigned long cache_size;
|
unsigned long cache_size;
|
||||||
int seed_len;
|
int seed_len;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ks#", &cache_size, &seed, &seed_len))
|
if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT, &cache_size, &seed, &seed_len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (seed_len != 32) {
|
if (seed_len != 32) {
|
||||||
|
|
@ -62,7 +70,7 @@ mkcache_bytes(PyObject *self, PyObject *args) {
|
||||||
ethash_cache cache;
|
ethash_cache cache;
|
||||||
cache.mem = malloc(cache_size);
|
cache.mem = malloc(cache_size);
|
||||||
ethash_mkcache(&cache, ¶ms, (uint8_t *) seed);
|
ethash_mkcache(&cache, ¶ms, (uint8_t *) seed);
|
||||||
PyObject * val = Py_BuildValue("s#", cache.mem, cache_size);
|
PyObject * val = Py_BuildValue(PY_STRING_FORMAT, cache.mem, cache_size);
|
||||||
free(cache.mem);
|
free(cache.mem);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +82,7 @@ calc_dataset_bytes(PyObject *self, PyObject *args) {
|
||||||
unsigned long full_size;
|
unsigned long full_size;
|
||||||
int cache_size;
|
int cache_size;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ks#", &full_size, &cache_bytes, &cache_size))
|
if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT, &full_size, &cache_bytes, &cache_size))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (full_size % MIX_WORDS != 0) {
|
if (full_size % MIX_WORDS != 0) {
|
||||||
|
|
@ -98,7 +106,7 @@ calc_dataset_bytes(PyObject *self, PyObject *args) {
|
||||||
cache.mem = (void *) cache_bytes;
|
cache.mem = (void *) cache_bytes;
|
||||||
void *mem = malloc(params.full_size);
|
void *mem = malloc(params.full_size);
|
||||||
ethash_compute_full_data(mem, ¶ms, &cache);
|
ethash_compute_full_data(mem, ¶ms, &cache);
|
||||||
PyObject * val = Py_BuildValue("s#", (char *) mem, full_size);
|
PyObject * val = Py_BuildValue(PY_STRING_FORMAT, (char *) mem, full_size);
|
||||||
free(mem);
|
free(mem);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +119,7 @@ hashimoto_light(PyObject *self, PyObject *args) {
|
||||||
unsigned long long nonce;
|
unsigned long long nonce;
|
||||||
int cache_size, header_size;
|
int cache_size, header_size;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ks#s#K", &full_size, &cache_bytes, &cache_size, &header, &header_size, &nonce))
|
if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT PY_STRING_FORMAT "K", &full_size, &cache_bytes, &cache_size, &header, &header_size, &nonce))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (full_size % MIX_WORDS != 0) {
|
if (full_size % MIX_WORDS != 0) {
|
||||||
|
|
@ -143,7 +151,7 @@ hashimoto_light(PyObject *self, PyObject *args) {
|
||||||
ethash_cache cache;
|
ethash_cache cache;
|
||||||
cache.mem = (void *) cache_bytes;
|
cache.mem = (void *) cache_bytes;
|
||||||
ethash_light(&out, &cache, ¶ms, (uint8_t *) header, nonce);
|
ethash_light(&out, &cache, ¶ms, (uint8_t *) header, nonce);
|
||||||
return Py_BuildValue("{s:s#,s:s#}",
|
return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "," PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "}",
|
||||||
"mix digest", out.mix_hash, 32,
|
"mix digest", out.mix_hash, 32,
|
||||||
"result", out.result, 32);
|
"result", out.result, 32);
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +163,7 @@ hashimoto_full(PyObject *self, PyObject *args) {
|
||||||
unsigned long long nonce;
|
unsigned long long nonce;
|
||||||
int full_size, header_size;
|
int full_size, header_size;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s#s#K", &full_bytes, &full_size, &header, &header_size, &nonce))
|
if (!PyArg_ParseTuple(args, PY_STRING_FORMAT PY_STRING_FORMAT "K", &full_bytes, &full_size, &header, &header_size, &nonce))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (full_size % MIX_WORDS != 0) {
|
if (full_size % MIX_WORDS != 0) {
|
||||||
|
|
@ -177,7 +185,7 @@ hashimoto_full(PyObject *self, PyObject *args) {
|
||||||
ethash_params params;
|
ethash_params params;
|
||||||
params.full_size = (size_t) full_size;
|
params.full_size = (size_t) full_size;
|
||||||
ethash_full(&out, (void *) full_bytes, ¶ms, (uint8_t *) header, nonce);
|
ethash_full(&out, (void *) full_bytes, ¶ms, (uint8_t *) header, nonce);
|
||||||
return Py_BuildValue("{s:s#, s:s#}",
|
return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT ", " PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "}",
|
||||||
"mix digest", out.mix_hash, 32,
|
"mix digest", out.mix_hash, 32,
|
||||||
"result", out.result, 32);
|
"result", out.result, 32);
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +198,7 @@ mine(PyObject *self, PyObject *args) {
|
||||||
uint64_t nonce = ((uint64_t) rand()) << 32 | rand();
|
uint64_t nonce = ((uint64_t) rand()) << 32 | rand();
|
||||||
int full_size, header_size, difficulty_size;
|
int full_size, header_size, difficulty_size;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s#s#s#", &full_bytes, &full_size, &header, &header_size, &difficulty, &difficulty_size))
|
if (!PyArg_ParseTuple(args, PY_STRING_FORMAT PY_STRING_FORMAT PY_STRING_FORMAT, &full_bytes, &full_size, &header, &header_size, &difficulty, &difficulty_size))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (full_size % MIX_WORDS != 0) {
|
if (full_size % MIX_WORDS != 0) {
|
||||||
|
|
@ -224,7 +232,7 @@ mine(PyObject *self, PyObject *args) {
|
||||||
// TODO: disagrees with the spec https://github.com/ethereum/wiki/wiki/Ethash#mining
|
// TODO: disagrees with the spec https://github.com/ethereum/wiki/wiki/Ethash#mining
|
||||||
} while (!ethash_check_difficulty(out.result, (const uint8_t *) difficulty));
|
} while (!ethash_check_difficulty(out.result, (const uint8_t *) difficulty));
|
||||||
|
|
||||||
return Py_BuildValue("{s:s#, s:s#, s:K}",
|
return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT ", " PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT ", " PY_CONST_STRING_FORMAT ":K}",
|
||||||
"mix digest", out.mix_hash, 32,
|
"mix digest", out.mix_hash, 32,
|
||||||
"result", out.result, 32,
|
"result", out.result, 32,
|
||||||
"nonce", nonce);
|
"nonce", nonce);
|
||||||
|
|
@ -245,7 +253,7 @@ get_seedhash(PyObject *self, PyObject *args) {
|
||||||
}
|
}
|
||||||
uint8_t seedhash[32];
|
uint8_t seedhash[32];
|
||||||
ethash_get_seedhash(seedhash, block_number);
|
ethash_get_seedhash(seedhash, block_number);
|
||||||
return Py_BuildValue("s#", (char *) seedhash, 32);
|
return Py_BuildValue(PY_STRING_FORMAT, (char *) seedhash, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef PyethashMethods[] =
|
static PyMethodDef PyethashMethods[] =
|
||||||
|
|
@ -287,6 +295,32 @@ static PyMethodDef PyethashMethods[] =
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
static struct PyModuleDef PyethashModule = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"pyethash",
|
||||||
|
"...",
|
||||||
|
-1,
|
||||||
|
PyethashMethods
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODINIT_FUNC PyInit_pyethash(void) {
|
||||||
|
PyObject *module = PyModule_Create(&PyethashModule);
|
||||||
|
// Following Spec: https://github.com/ethereum/wiki/wiki/Ethash#definitions
|
||||||
|
PyModule_AddIntConstant(module, "REVISION", (long) REVISION);
|
||||||
|
PyModule_AddIntConstant(module, "DATASET_BYTES_INIT", (long) DATASET_BYTES_INIT);
|
||||||
|
PyModule_AddIntConstant(module, "DATASET_BYTES_GROWTH", (long) DATASET_BYTES_GROWTH);
|
||||||
|
PyModule_AddIntConstant(module, "CACHE_BYTES_INIT", (long) CACHE_BYTES_INIT);
|
||||||
|
PyModule_AddIntConstant(module, "CACHE_BYTES_GROWTH", (long) CACHE_BYTES_GROWTH);
|
||||||
|
PyModule_AddIntConstant(module, "EPOCH_LENGTH", (long) EPOCH_LENGTH);
|
||||||
|
PyModule_AddIntConstant(module, "MIX_BYTES", (long) MIX_BYTES);
|
||||||
|
PyModule_AddIntConstant(module, "HASH_BYTES", (long) HASH_BYTES);
|
||||||
|
PyModule_AddIntConstant(module, "DATASET_PARENTS", (long) DATASET_PARENTS);
|
||||||
|
PyModule_AddIntConstant(module, "CACHE_ROUNDS", (long) CACHE_ROUNDS);
|
||||||
|
PyModule_AddIntConstant(module, "ACCESSES", (long) ACCESSES);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
#else
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
initpyethash(void) {
|
initpyethash(void) {
|
||||||
PyObject *module = Py_InitModule("pyethash", PyethashMethods);
|
PyObject *module = Py_InitModule("pyethash", PyethashMethods);
|
||||||
|
|
@ -303,3 +337,4 @@ initpyethash(void) {
|
||||||
PyModule_AddIntConstant(module, "CACHE_ROUNDS", (long) CACHE_ROUNDS);
|
PyModule_AddIntConstant(module, "CACHE_ROUNDS", (long) CACHE_ROUNDS);
|
||||||
PyModule_AddIntConstant(module, "ACCESSES", (long) ACCESSES);
|
PyModule_AddIntConstant(module, "ACCESSES", (long) ACCESSES);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
39
Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt
generated
vendored
39
Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt
generated
vendored
|
|
@ -1,5 +1,30 @@
|
||||||
|
if (MSVC)
|
||||||
|
if (NOT BOOST_ROOT)
|
||||||
|
set (BOOST_ROOT "$ENV{BOOST_ROOT}")
|
||||||
|
endif()
|
||||||
|
set (CMAKE_PREFIX_PATH BOOST_ROOT)
|
||||||
|
endif()
|
||||||
|
|
||||||
IF( NOT Boost_FOUND )
|
IF( NOT Boost_FOUND )
|
||||||
find_package(Boost COMPONENTS unit_test_framework)
|
# use multithreaded boost libraries, with -mt suffix
|
||||||
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
# TODO handle other msvc versions or it will fail find them
|
||||||
|
set(Boost_COMPILER -vc120)
|
||||||
|
# use static boost libraries *.lib
|
||||||
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
|
elseif (APPLE)
|
||||||
|
|
||||||
|
# use static boost libraries *.a
|
||||||
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
|
|
||||||
|
elseif (UNIX)
|
||||||
|
# use dynamic boost libraries .dll
|
||||||
|
set(Boost_USE_STATIC_LIBS OFF)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
find_package(Boost 1.48.0 COMPONENTS unit_test_framework system filesystem)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF( Boost_FOUND )
|
IF( Boost_FOUND )
|
||||||
|
|
@ -8,8 +33,9 @@ IF( Boost_FOUND )
|
||||||
|
|
||||||
link_directories ( ${Boost_LIBRARY_DIRS} )
|
link_directories ( ${Boost_LIBRARY_DIRS} )
|
||||||
file(GLOB HEADERS "*.h")
|
file(GLOB HEADERS "*.h")
|
||||||
|
if (NOT MSVC)
|
||||||
ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK)
|
ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK)
|
||||||
|
endif()
|
||||||
if (NOT CRYPTOPP_FOUND)
|
if (NOT CRYPTOPP_FOUND)
|
||||||
find_package (CryptoPP)
|
find_package (CryptoPP)
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -18,8 +44,15 @@ IF( Boost_FOUND )
|
||||||
add_definitions(-DWITH_CRYPTOPP)
|
add_definitions(-DWITH_CRYPTOPP)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (NOT MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable (Test test.cpp ${HEADERS})
|
add_executable (Test test.cpp ${HEADERS})
|
||||||
target_link_libraries (Test ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${ETHHASH_LIBS})
|
target_link_libraries(Test ${ETHHASH_LIBS})
|
||||||
|
target_link_libraries(Test ${Boost_FILESYSTEM_LIBRARIES})
|
||||||
|
target_link_libraries(Test ${Boost_SYSTEM_LIBRARIES})
|
||||||
|
target_link_libraries (Test ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||||
|
|
||||||
if (CRYPTOPP_FOUND)
|
if (CRYPTOPP_FOUND)
|
||||||
TARGET_LINK_LIBRARIES(Test ${CRYPTOPP_LIBRARIES})
|
TARGET_LINK_LIBRARIES(Test ${CRYPTOPP_LIBRARIES})
|
||||||
|
|
|
||||||
164
Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp
generated
vendored
164
Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp
generated
vendored
|
|
@ -2,6 +2,7 @@
|
||||||
#include <libethash/fnv.h>
|
#include <libethash/fnv.h>
|
||||||
#include <libethash/ethash.h>
|
#include <libethash/ethash.h>
|
||||||
#include <libethash/internal.h>
|
#include <libethash/internal.h>
|
||||||
|
#include <libethash/io.h>
|
||||||
|
|
||||||
#ifdef WITH_CRYPTOPP
|
#ifdef WITH_CRYPTOPP
|
||||||
|
|
||||||
|
|
@ -14,13 +15,23 @@
|
||||||
#define BOOST_TEST_MODULE Daggerhashimoto
|
#define BOOST_TEST_MODULE Daggerhashimoto
|
||||||
#define BOOST_TEST_MAIN
|
#define BOOST_TEST_MAIN
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
std::string bytesToHexString(const uint8_t *str, const size_t s) {
|
using namespace std;
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
// Just an alloca "wrapper" to silence uint64_t to size_t conversion warnings in windows
|
||||||
|
// consider replacing alloca calls with something better though!
|
||||||
|
#define our_alloca(param__) alloca((size_t)(param__))
|
||||||
|
|
||||||
|
std::string bytesToHexString(const uint8_t *str, const uint64_t s) {
|
||||||
std::ostringstream ret;
|
std::ostringstream ret;
|
||||||
|
|
||||||
for (int i = 0; i < s; ++i)
|
for (size_t i = 0; i < s; ++i)
|
||||||
ret << std::hex << std::setfill('0') << std::setw(2) << std::nouppercase << (int) str[i];
|
ret << std::hex << std::setfill('0') << std::setw(2) << std::nouppercase << (int) str[i];
|
||||||
|
|
||||||
return ret.str();
|
return ret.str();
|
||||||
|
|
@ -108,9 +119,9 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
|
||||||
params.cache_size = 1024;
|
params.cache_size = 1024;
|
||||||
params.full_size = 1024 * 32;
|
params.full_size = 1024 * 32;
|
||||||
ethash_cache cache;
|
ethash_cache cache;
|
||||||
cache.mem = alloca(params.cache_size);
|
cache.mem = our_alloca(params.cache_size);
|
||||||
ethash_mkcache(&cache, ¶ms, seed);
|
ethash_mkcache(&cache, ¶ms, seed);
|
||||||
node *full_mem = (node *) alloca(params.full_size);
|
node *full_mem = (node *) our_alloca(params.full_size);
|
||||||
ethash_compute_full_data(full_mem, ¶ms, &cache);
|
ethash_compute_full_data(full_mem, ¶ms, &cache);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -226,3 +237,146 @@ BOOST_AUTO_TEST_CASE(ethash_check_difficulty_check) {
|
||||||
!ethash_check_difficulty(hash, target),
|
!ethash_check_difficulty(hash, target),
|
||||||
"\nexpected \"" << hash << "\" to have more difficulty than \"" << target << "\"\n");
|
"\nexpected \"" << hash << "\" to have more difficulty than \"" << target << "\"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_ethash_dir_creation) {
|
||||||
|
ethash_blockhash_t seedhash;
|
||||||
|
memset(&seedhash, 0, 32);
|
||||||
|
BOOST_REQUIRE_EQUAL(
|
||||||
|
ETHASH_IO_MEMO_MISMATCH,
|
||||||
|
ethash_io_prepare("./test_ethash_directory/", seedhash)
|
||||||
|
);
|
||||||
|
|
||||||
|
// let's make sure that the directory was created
|
||||||
|
BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/")));
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
fs::remove_all("./test_ethash_directory/");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_ethash_io_write_files_are_created) {
|
||||||
|
ethash_blockhash_t seedhash;
|
||||||
|
static const int blockn = 0;
|
||||||
|
ethash_get_seedhash((uint8_t*)&seedhash, blockn);
|
||||||
|
BOOST_REQUIRE_EQUAL(
|
||||||
|
ETHASH_IO_MEMO_MISMATCH,
|
||||||
|
ethash_io_prepare("./test_ethash_directory/", seedhash)
|
||||||
|
);
|
||||||
|
|
||||||
|
// let's make sure that the directory was created
|
||||||
|
BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/")));
|
||||||
|
|
||||||
|
ethash_cache cache;
|
||||||
|
ethash_params params;
|
||||||
|
uint8_t *data;
|
||||||
|
uint64_t size;
|
||||||
|
ethash_params_init(¶ms, blockn);
|
||||||
|
params.cache_size = 1024;
|
||||||
|
params.full_size = 1024 * 32;
|
||||||
|
cache.mem = our_alloca(params.cache_size);
|
||||||
|
ethash_mkcache(&cache, ¶ms, (uint8_t*)&seedhash);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(
|
||||||
|
ethash_io_write("./test_ethash_directory/", ¶ms, seedhash, &cache, &data, &size)
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(fs::exists(fs::path("./test_ethash_directory/full")));
|
||||||
|
BOOST_REQUIRE(fs::exists(fs::path("./test_ethash_directory/full.info")));
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
fs::remove_all("./test_ethash_directory/");
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_ethash_io_memo_file_match) {
|
||||||
|
ethash_blockhash_t seedhash;
|
||||||
|
static const int blockn = 0;
|
||||||
|
ethash_get_seedhash((uint8_t*)&seedhash, blockn);
|
||||||
|
BOOST_REQUIRE_EQUAL(
|
||||||
|
ETHASH_IO_MEMO_MISMATCH,
|
||||||
|
ethash_io_prepare("./test_ethash_directory/", seedhash)
|
||||||
|
);
|
||||||
|
|
||||||
|
// let's make sure that the directory was created
|
||||||
|
BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/")));
|
||||||
|
|
||||||
|
ethash_cache cache;
|
||||||
|
ethash_params params;
|
||||||
|
uint8_t *data;
|
||||||
|
uint64_t size;
|
||||||
|
ethash_params_init(¶ms, blockn);
|
||||||
|
params.cache_size = 1024;
|
||||||
|
params.full_size = 1024 * 32;
|
||||||
|
cache.mem = our_alloca(params.cache_size);
|
||||||
|
ethash_mkcache(&cache, ¶ms, (uint8_t*)&seedhash);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(
|
||||||
|
ethash_io_write("./test_ethash_directory/", ¶ms, seedhash, &cache, &data, &size)
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(fs::exists(fs::path("./test_ethash_directory/full")));
|
||||||
|
BOOST_REQUIRE(fs::exists(fs::path("./test_ethash_directory/full.info")));
|
||||||
|
|
||||||
|
BOOST_REQUIRE_EQUAL(
|
||||||
|
ETHASH_IO_MEMO_MATCH,
|
||||||
|
ethash_io_prepare("./test_ethash_directory/", seedhash)
|
||||||
|
);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
fs::remove_all("./test_ethash_directory/");
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// could have used dev::contentsNew but don't wanna try to import
|
||||||
|
// libdevcore just for one function
|
||||||
|
static std::vector<char> readFileIntoVector(char const* filename)
|
||||||
|
{
|
||||||
|
ifstream ifs(filename, ios::binary|ios::ate);
|
||||||
|
ifstream::pos_type pos = ifs.tellg();
|
||||||
|
|
||||||
|
std::vector<char> result((unsigned int)pos);
|
||||||
|
|
||||||
|
ifs.seekg(0, ios::beg);
|
||||||
|
ifs.read(&result[0], pos);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_ethash_io_memo_file_contents) {
|
||||||
|
ethash_blockhash_t seedhash;
|
||||||
|
static const int blockn = 0;
|
||||||
|
ethash_get_seedhash((uint8_t*)&seedhash, blockn);
|
||||||
|
BOOST_REQUIRE_EQUAL(
|
||||||
|
ETHASH_IO_MEMO_MISMATCH,
|
||||||
|
ethash_io_prepare("./test_ethash_directory/", seedhash)
|
||||||
|
);
|
||||||
|
|
||||||
|
// let's make sure that the directory was created
|
||||||
|
BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/")));
|
||||||
|
|
||||||
|
ethash_cache cache;
|
||||||
|
ethash_params params;
|
||||||
|
uint8_t *data;
|
||||||
|
uint64_t size;
|
||||||
|
ethash_params_init(¶ms, blockn);
|
||||||
|
params.cache_size = 1024;
|
||||||
|
params.full_size = 1024 * 32;
|
||||||
|
cache.mem = our_alloca(params.cache_size);
|
||||||
|
ethash_mkcache(&cache, ¶ms, (uint8_t*)&seedhash);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(
|
||||||
|
ethash_io_write("./test_ethash_directory/", ¶ms, seedhash, &cache, &data, &size)
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(fs::exists(fs::path("./test_ethash_directory/full")));
|
||||||
|
BOOST_REQUIRE(fs::exists(fs::path("./test_ethash_directory/full.info")));
|
||||||
|
|
||||||
|
char expect_buffer[DAG_MEMO_BYTESIZE];
|
||||||
|
ethash_io_serialize_info(REVISION, seedhash, expect_buffer);
|
||||||
|
auto vec = readFileIntoVector("./test_ethash_directory/full.info");
|
||||||
|
BOOST_REQUIRE_EQUAL(vec.size(), DAG_MEMO_BYTESIZE);
|
||||||
|
BOOST_REQUIRE(memcmp(expect_buffer, &vec[0], DAG_MEMO_BYTESIZE) == 0);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
fs::remove_all("./test_ethash_directory/");
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
|
||||||
20
Godeps/_workspace/src/github.com/ethereum/ethash/test/go/test.sh
generated
vendored
20
Godeps/_workspace/src/github.com/ethereum/ethash/test/go/test.sh
generated
vendored
|
|
@ -1,20 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Strict mode
|
|
||||||
set -e
|
|
||||||
|
|
||||||
SOURCE="${BASH_SOURCE[0]}"
|
|
||||||
while [ -h "$SOURCE" ]; do
|
|
||||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
|
||||||
SOURCE="$(readlink "$SOURCE")"
|
|
||||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
|
|
||||||
done
|
|
||||||
TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
|
||||||
|
|
||||||
export GOPATH=${HOME}/.go
|
|
||||||
export PATH=$PATH:$GOPATH/bin
|
|
||||||
echo "# getting go dependencies (can take some time)..."
|
|
||||||
cd ${TEST_DIR}/../.. && go get
|
|
||||||
cd ${GOPATH}/src/github.com/ethereum/go-ethereum
|
|
||||||
git checkout poc-9
|
|
||||||
cd ${TEST_DIR} && go test
|
|
||||||
|
|
@ -653,6 +653,9 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
|
||||||
}
|
}
|
||||||
sender.lock.Unlock()
|
sender.lock.Unlock()
|
||||||
|
|
||||||
|
/* @zelig !!!
|
||||||
|
requested 5 hashes from both A & B. A responds sooner then B, process blocks. Close section.
|
||||||
|
delayed B sends you block ... UNREQUESTED. Blocked
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
plog.DebugDetailf("AddBlock: unrequested block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
|
plog.DebugDetailf("AddBlock: unrequested block %s received from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
|
||||||
sender.addError(ErrUnrequestedBlock, "%x", hash)
|
sender.addError(ErrUnrequestedBlock, "%x", hash)
|
||||||
|
|
@ -662,6 +665,7 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
|
||||||
self.status.lock.Unlock()
|
self.status.lock.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
return
|
return
|
||||||
|
|
@ -683,6 +687,8 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@zelig needs discussing
|
||||||
// validate block for PoW
|
// validate block for PoW
|
||||||
if !self.verifyPoW(block) {
|
if !self.verifyPoW(block) {
|
||||||
plog.Warnf("AddBlock: invalid PoW on block %s from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
|
plog.Warnf("AddBlock: invalid PoW on block %s from peer <%s> (head: %s)", hex(hash), peerId, hex(sender.currentBlockHash))
|
||||||
|
|
@ -694,6 +700,7 @@ func (self *BlockPool) AddBlock(block *types.Block, peerId string) {
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
node.block = block
|
node.block = block
|
||||||
node.blockBy = peerId
|
node.blockBy = peerId
|
||||||
|
|
@ -761,10 +768,10 @@ func (self *BlockPool) checkTD(nodes ...*node) {
|
||||||
if n.td != nil {
|
if n.td != nil {
|
||||||
plog.DebugDetailf("peer td %v =?= block td %v", n.td, n.block.Td)
|
plog.DebugDetailf("peer td %v =?= block td %v", n.td, n.block.Td)
|
||||||
if n.td.Cmp(n.block.Td) != 0 {
|
if n.td.Cmp(n.block.Td) != 0 {
|
||||||
self.peers.peerError(n.blockBy, ErrIncorrectTD, "on block %x", n.hash)
|
//self.peers.peerError(n.blockBy, ErrIncorrectTD, "on block %x", n.hash)
|
||||||
self.status.lock.Lock()
|
//self.status.lock.Lock()
|
||||||
self.status.badPeers[n.blockBy]++
|
//self.status.badPeers[n.blockBy]++
|
||||||
self.status.lock.Unlock()
|
//self.status.lock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,8 @@ func TestErrInsufficientChainInfo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIncorrectTD(t *testing.T) {
|
func TestIncorrectTD(t *testing.T) {
|
||||||
|
t.Skip() // @zelig this one requires fixing for the TD
|
||||||
|
|
||||||
test.LogInit()
|
test.LogInit()
|
||||||
_, blockPool, blockPoolTester := newTestBlockPool(t)
|
_, blockPool, blockPoolTester := newTestBlockPool(t)
|
||||||
blockPoolTester.blockChain[0] = nil
|
blockPoolTester.blockChain[0] = nil
|
||||||
|
|
|
||||||
|
|
@ -477,8 +477,8 @@ func (self *peer) getBlockHashes() bool {
|
||||||
// XXX added currentBlock check (?)
|
// XXX added currentBlock check (?)
|
||||||
if self.currentBlock != nil && self.currentBlock.Td != nil {
|
if self.currentBlock != nil && self.currentBlock.Td != nil {
|
||||||
if self.td.Cmp(self.currentBlock.Td) != 0 {
|
if self.td.Cmp(self.currentBlock.Td) != 0 {
|
||||||
self.addError(ErrIncorrectTD, "on block %x", self.currentBlockHash)
|
//self.addError(ErrIncorrectTD, "on block %x", self.currentBlockHash)
|
||||||
self.bp.status.badPeers[self.id]++
|
//self.bp.status.badPeers[self.id]++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headKey := self.parentHash
|
headKey := self.parentHash
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ func (self *section) addSectionToBlockChain(p *peer) {
|
||||||
}
|
}
|
||||||
self.bp.lock.Unlock()
|
self.bp.lock.Unlock()
|
||||||
|
|
||||||
plog.Infof("[%s] insert %v blocks [%v/%v] into blockchain", sectionhex(self), len(blocks), hex(blocks[0].Hash()), hex(blocks[len(blocks)-1].Hash()))
|
plog.Debugf("[%s] insert %v blocks [%v/%v] into blockchain", sectionhex(self), len(blocks), hex(blocks[0].Hash()), hex(blocks[len(blocks)-1].Hash()))
|
||||||
err := self.bp.insertChain(blocks)
|
err := self.bp.insertChain(blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.invalid = true
|
self.invalid = true
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
|
|
@ -25,8 +26,6 @@ func (js *jsre) adminBindings() {
|
||||||
admin := t.Object()
|
admin := t.Object()
|
||||||
admin.Set("suggestPeer", js.suggestPeer)
|
admin.Set("suggestPeer", js.suggestPeer)
|
||||||
admin.Set("startRPC", js.startRPC)
|
admin.Set("startRPC", js.startRPC)
|
||||||
admin.Set("startMining", js.startMining)
|
|
||||||
admin.Set("stopMining", js.stopMining)
|
|
||||||
admin.Set("nodeInfo", js.nodeInfo)
|
admin.Set("nodeInfo", js.nodeInfo)
|
||||||
admin.Set("peers", js.peers)
|
admin.Set("peers", js.peers)
|
||||||
admin.Set("newAccount", js.newAccount)
|
admin.Set("newAccount", js.newAccount)
|
||||||
|
|
@ -34,6 +33,58 @@ func (js *jsre) adminBindings() {
|
||||||
admin.Set("import", js.importChain)
|
admin.Set("import", js.importChain)
|
||||||
admin.Set("export", js.exportChain)
|
admin.Set("export", js.exportChain)
|
||||||
admin.Set("dumpBlock", js.dumpBlock)
|
admin.Set("dumpBlock", js.dumpBlock)
|
||||||
|
admin.Set("verbosity", js.verbosity)
|
||||||
|
admin.Set("backtrace", js.backtrace)
|
||||||
|
|
||||||
|
admin.Set("miner", struct{}{})
|
||||||
|
t, _ = admin.Get("miner")
|
||||||
|
miner := t.Object()
|
||||||
|
miner.Set("start", js.startMining)
|
||||||
|
miner.Set("stop", js.stopMining)
|
||||||
|
miner.Set("hashrate", js.hashrate)
|
||||||
|
miner.Set("setExtra", js.setExtra)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (js *jsre) setExtra(call otto.FunctionCall) otto.Value {
|
||||||
|
extra, err := call.Argument(0).ToString()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return otto.UndefinedValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(extra) > 1024 {
|
||||||
|
fmt.Println("error: cannot exceed 1024 bytes")
|
||||||
|
return otto.UndefinedValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
js.ethereum.Miner().SetExtra([]byte(extra))
|
||||||
|
return otto.UndefinedValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (js *jsre) hashrate(otto.FunctionCall) otto.Value {
|
||||||
|
return js.re.ToVal(js.ethereum.Miner().HashRate())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (js *jsre) backtrace(call otto.FunctionCall) otto.Value {
|
||||||
|
tracestr, err := call.Argument(0).ToString()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return otto.UndefinedValue()
|
||||||
|
}
|
||||||
|
glog.GetTraceLocation().Set(tracestr)
|
||||||
|
|
||||||
|
return otto.UndefinedValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (js *jsre) verbosity(call otto.FunctionCall) otto.Value {
|
||||||
|
v, err := call.Argument(0).ToInteger()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return otto.UndefinedValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.SetV(int(v))
|
||||||
|
return otto.UndefinedValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
|
func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ClientIdentifier = "Geth"
|
ClientIdentifier = "Geth"
|
||||||
Version = "0.9.4"
|
Version = "0.9.7"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -234,6 +234,8 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
|
||||||
utils.ProtocolVersionFlag,
|
utils.ProtocolVersionFlag,
|
||||||
utils.NetworkIdFlag,
|
utils.NetworkIdFlag,
|
||||||
utils.RPCCORSDomainFlag,
|
utils.RPCCORSDomainFlag,
|
||||||
|
utils.BacktraceAtFlag,
|
||||||
|
utils.LogToStdErrFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
// missing:
|
// missing:
|
||||||
|
|
@ -478,7 +480,7 @@ func makedag(ctx *cli.Context) {
|
||||||
chain, _, _ := utils.GetChain(ctx)
|
chain, _, _ := utils.GetChain(ctx)
|
||||||
pow := ethash.New(chain)
|
pow := ethash.New(chain)
|
||||||
fmt.Println("making cache")
|
fmt.Println("making cache")
|
||||||
pow.UpdateCache(true)
|
pow.UpdateCache(0, true)
|
||||||
fmt.Println("making DAG")
|
fmt.Println("making DAG")
|
||||||
pow.UpdateDAG()
|
pow.UpdateDAG()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
|
|
@ -184,6 +185,15 @@ var (
|
||||||
Usage: "JS library path to be used with console and js subcommands",
|
Usage: "JS library path to be used with console and js subcommands",
|
||||||
Value: ".",
|
Value: ".",
|
||||||
}
|
}
|
||||||
|
BacktraceAtFlag = cli.GenericFlag{
|
||||||
|
Name: "backtrace_at",
|
||||||
|
Usage: "When set to a file and line number holding a logging statement a stack trace will be written to the Info log",
|
||||||
|
Value: glog.GetTraceLocation(),
|
||||||
|
}
|
||||||
|
LogToStdErrFlag = cli.BoolFlag{
|
||||||
|
Name: "logtostderr",
|
||||||
|
Usage: "Logs are written to standard error instead of to files.",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetNAT(ctx *cli.Context) nat.Interface {
|
func GetNAT(ctx *cli.Context) nat.Interface {
|
||||||
|
|
@ -213,6 +223,11 @@ func GetNodeKey(ctx *cli.Context) (key *ecdsa.PrivateKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
||||||
|
// Set verbosity on glog
|
||||||
|
glog.SetV(ctx.GlobalInt(LogLevelFlag.Name))
|
||||||
|
// Set the log type
|
||||||
|
glog.SetToStderr(ctx.GlobalBool(LogToStdErrFlag.Name))
|
||||||
|
|
||||||
return ð.Config{
|
return ð.Config{
|
||||||
Name: common.MakeName(clientID, version),
|
Name: common.MakeName(clientID, version),
|
||||||
DataDir: ctx.GlobalString(DataDirFlag.Name),
|
DataDir: ctx.GlobalString(DataDirFlag.Name),
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,23 @@ func (bc *BlockCache) Push(block *types.Block) {
|
||||||
bc.hashes[len(bc.hashes)-1] = hash
|
bc.hashes[len(bc.hashes)-1] = hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bc *BlockCache) Delete(hash common.Hash) {
|
||||||
|
bc.mu.Lock()
|
||||||
|
defer bc.mu.Unlock()
|
||||||
|
|
||||||
|
if _, ok := bc.blocks[hash]; ok {
|
||||||
|
delete(bc.blocks, hash)
|
||||||
|
for i, h := range bc.hashes {
|
||||||
|
if hash == h {
|
||||||
|
bc.hashes = bc.hashes[:i+copy(bc.hashes[i:], bc.hashes[i+1:])]
|
||||||
|
// or ? => bc.hashes = append(bc.hashes[:i], bc.hashes[i+1]...)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (bc *BlockCache) Get(hash common.Hash) *types.Block {
|
func (bc *BlockCache) Get(hash common.Hash) *types.Block {
|
||||||
bc.mu.RLock()
|
bc.mu.RLock()
|
||||||
defer bc.mu.RUnlock()
|
defer bc.mu.RUnlock()
|
||||||
|
|
@ -71,3 +88,14 @@ func (bc *BlockCache) Has(hash common.Hash) bool {
|
||||||
_, ok := bc.blocks[hash]
|
_, ok := bc.blocks[hash]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bc *BlockCache) Each(cb func(int, *types.Block)) {
|
||||||
|
bc.mu.Lock()
|
||||||
|
defer bc.mu.Unlock()
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for _, block := range bc.blocks {
|
||||||
|
cb(i, block)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,3 +46,15 @@ func TestInclusion(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeletion(t *testing.T) {
|
||||||
|
chain := newChain(3)
|
||||||
|
cache := NewBlockCache(3)
|
||||||
|
insertChainCache(cache, chain)
|
||||||
|
|
||||||
|
cache.Delete(chain[1].Hash())
|
||||||
|
|
||||||
|
if cache.Has(chain[1].Hash()) {
|
||||||
|
t.Errorf("expected %x not to be included")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
@ -90,7 +91,8 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
|
||||||
receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative)
|
receipt := types.NewReceipt(statedb.Root().Bytes(), cumulative)
|
||||||
receipt.SetLogs(statedb.Logs())
|
receipt.SetLogs(statedb.Logs())
|
||||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||||
chainlogger.Debugln(receipt)
|
|
||||||
|
glog.V(logger.Debug).Infoln(receipt)
|
||||||
|
|
||||||
// Notify all subscribers
|
// Notify all subscribers
|
||||||
if !transientProcess {
|
if !transientProcess {
|
||||||
|
|
@ -120,7 +122,7 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statelogger.Infoln("TX err:", err)
|
glog.V(logger.Core).Infoln("TX err:", err)
|
||||||
}
|
}
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
|
|
||||||
|
|
@ -165,16 +167,10 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
|
||||||
// Create a new state based on the parent's root (e.g., create copy)
|
// Create a new state based on the parent's root (e.g., create copy)
|
||||||
state := state.New(parent.Root(), sm.db)
|
state := state.New(parent.Root(), sm.db)
|
||||||
|
|
||||||
// track (possible) uncle block
|
|
||||||
var uncle bool
|
|
||||||
// Block validation
|
// Block validation
|
||||||
if err = sm.ValidateHeader(block.Header(), parent.Header()); err != nil {
|
if err = sm.ValidateHeader(block.Header(), parent.Header()); err != nil {
|
||||||
if err != BlockEqualTSErr {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = nil
|
|
||||||
uncle = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// There can be at most two uncles
|
// There can be at most two uncles
|
||||||
if len(block.Uncles()) > 2 {
|
if len(block.Uncles()) > 2 {
|
||||||
|
|
@ -231,23 +227,14 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big
|
||||||
// Sync the current block's state to the database
|
// Sync the current block's state to the database
|
||||||
state.Sync()
|
state.Sync()
|
||||||
|
|
||||||
if !uncle {
|
|
||||||
// Remove transactions from the pool
|
// Remove transactions from the pool
|
||||||
sm.txpool.RemoveSet(block.Transactions())
|
sm.txpool.RemoveSet(block.Transactions())
|
||||||
}
|
|
||||||
|
|
||||||
// This puts transactions in a extra db for rpc
|
// This puts transactions in a extra db for rpc
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
putTx(sm.extraDb, tx, block, uint64(i))
|
putTx(sm.extraDb, tx, block, uint64(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
if uncle {
|
|
||||||
chainlogger.Infof("found possible uncle block #%d (%x...)\n", header.Number, block.Hash().Bytes()[0:4])
|
|
||||||
return td, nil, BlockEqualTSErr
|
|
||||||
} else {
|
|
||||||
chainlogger.Infof("processed block #%d (%d TXs %d UNCs) (%x...)\n", header.Number, len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4])
|
|
||||||
}
|
|
||||||
|
|
||||||
return td, state.Logs(), nil
|
return td, state.Logs(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,7 +259,8 @@ func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
|
||||||
return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b)
|
return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if int64(block.Time) > time.Now().Unix() {
|
// Allow future blocks up to 10 seconds
|
||||||
|
if int64(block.Time) > time.Now().Unix()+4 {
|
||||||
return BlockFutureErr
|
return BlockFutureErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,15 +268,15 @@ func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
|
||||||
return BlockNumberErr
|
return BlockNumberErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if block.Time <= parent.Time {
|
||||||
|
return BlockEqualTSErr //ValidationError("Block timestamp equal or less than previous block (%v - %v)", block.Time, parent.Time)
|
||||||
|
}
|
||||||
|
|
||||||
// Verify the nonce of the block. Return an error if it's not valid
|
// Verify the nonce of the block. Return an error if it's not valid
|
||||||
if !sm.Pow.Verify(types.NewBlockWithHeader(block)) {
|
if !sm.Pow.Verify(types.NewBlockWithHeader(block)) {
|
||||||
return ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
|
return ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.Time <= parent.Time {
|
|
||||||
return BlockEqualTSErr //ValidationError("Block timestamp equal or less than previous block (%v - %v)", block.Time, parent.Time)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,7 +330,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
|
||||||
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sm.ValidateHeader(uncle, ancestorHeaders[uncle.ParentHash]); err != nil && err != BlockEqualTSErr {
|
if err := sm.ValidateHeader(uncle, ancestorHeaders[uncle.ParentHash]); err != nil {
|
||||||
return ValidationError(fmt.Sprintf("%v", err))
|
return ValidationError(fmt.Sprintf("%v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -371,7 +359,7 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
|
||||||
func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint64) {
|
func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint64) {
|
||||||
rlpEnc, err := rlp.EncodeToBytes(tx)
|
rlpEnc, err := rlp.EncodeToBytes(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statelogger.Infoln("Failed encoding tx", err)
|
glog.V(logger.Debug).Infoln("Failed encoding tx", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
db.Put(tx.Hash().Bytes(), rlpEnc)
|
db.Put(tx.Hash().Bytes(), rlpEnc)
|
||||||
|
|
@ -386,7 +374,7 @@ func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint
|
||||||
txExtra.Index = i
|
txExtra.Index = i
|
||||||
rlpMeta, err := rlp.EncodeToBytes(txExtra)
|
rlpMeta, err := rlp.EncodeToBytes(txExtra)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statelogger.Infoln("Failed encoding meta", err)
|
glog.V(logger.Debug).Infoln("Failed encoding tx meta data", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
|
db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,11 @@ func TestNumber(t *testing.T) {
|
||||||
bp, chain := proc()
|
bp, chain := proc()
|
||||||
block1 := chain.NewBlock(common.Address{})
|
block1 := chain.NewBlock(common.Address{})
|
||||||
block1.Header().Number = big.NewInt(3)
|
block1.Header().Number = big.NewInt(3)
|
||||||
|
block1.Header().Time--
|
||||||
|
|
||||||
err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header())
|
err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header())
|
||||||
if err != BlockNumberErr {
|
if err != BlockNumberErr {
|
||||||
t.Errorf("expected block number error")
|
t.Errorf("expected block number error %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
block1 = chain.NewBlock(common.Address{})
|
block1 = chain.NewBlock(common.Address{})
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ func NewCanonical(n int, db common.Database) (*BlockProcessor, error) {
|
||||||
|
|
||||||
// block time is fixed at 10 seconds
|
// block time is fixed at 10 seconds
|
||||||
func newBlockFromParent(addr common.Address, parent *types.Block) *types.Block {
|
func newBlockFromParent(addr common.Address, parent *types.Block) *types.Block {
|
||||||
block := types.NewBlock(parent.Hash(), addr, parent.Root(), common.BigPow(2, 32), 0, "")
|
block := types.NewBlock(parent.Hash(), addr, parent.Root(), common.BigPow(2, 32), 0, nil)
|
||||||
block.SetUncles(nil)
|
block.SetUncles(nil)
|
||||||
block.SetTransactions(nil)
|
block.SetTransactions(nil)
|
||||||
block.SetReceipts(nil)
|
block.SetReceipts(nil)
|
||||||
|
|
@ -109,6 +109,7 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Dat
|
||||||
// Effectively a fork factory
|
// Effectively a fork factory
|
||||||
func newChainManager(block *types.Block, eventMux *event.TypeMux, db common.Database) *ChainManager {
|
func newChainManager(block *types.Block, eventMux *event.TypeMux, db common.Database) *ChainManager {
|
||||||
bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
|
bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
|
||||||
|
bc.futureBlocks = NewBlockCache(1000)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
bc.Reset()
|
bc.Reset()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
@ -95,6 +97,7 @@ type ChainManager struct {
|
||||||
txState *state.ManagedState
|
txState *state.ManagedState
|
||||||
|
|
||||||
cache *BlockCache
|
cache *BlockCache
|
||||||
|
futureBlocks *BlockCache
|
||||||
|
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
}
|
}
|
||||||
|
|
@ -106,6 +109,7 @@ func NewChainManager(blockDb, stateDb common.Database, mux *event.TypeMux) *Chai
|
||||||
// Take ownership of this particular state
|
// Take ownership of this particular state
|
||||||
bc.txState = state.ManageState(bc.State().Copy())
|
bc.txState = state.ManageState(bc.State().Copy())
|
||||||
|
|
||||||
|
bc.futureBlocks = NewBlockCache(254)
|
||||||
bc.makeCache()
|
bc.makeCache()
|
||||||
|
|
||||||
go bc.update()
|
go bc.update()
|
||||||
|
|
@ -186,7 +190,9 @@ func (bc *ChainManager) setLastBlock() {
|
||||||
bc.Reset()
|
bc.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
chainlogger.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
|
if glog.V(logger.Info) {
|
||||||
|
glog.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *ChainManager) makeCache() {
|
func (bc *ChainManager) makeCache() {
|
||||||
|
|
@ -222,7 +228,7 @@ func (bc *ChainManager) NewBlock(coinbase common.Address) *types.Block {
|
||||||
root,
|
root,
|
||||||
common.BigPow(2, 32),
|
common.BigPow(2, 32),
|
||||||
0,
|
0,
|
||||||
"")
|
nil)
|
||||||
block.SetUncles(nil)
|
block.SetUncles(nil)
|
||||||
block.SetTransactions(nil)
|
block.SetTransactions(nil)
|
||||||
block.SetReceipts(nil)
|
block.SetReceipts(nil)
|
||||||
|
|
@ -284,7 +290,8 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
|
||||||
func (self *ChainManager) Export(w io.Writer) error {
|
func (self *ChainManager) Export(w io.Writer) error {
|
||||||
self.mu.RLock()
|
self.mu.RLock()
|
||||||
defer self.mu.RUnlock()
|
defer self.mu.RUnlock()
|
||||||
chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)
|
glog.V(logger.Info).Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)
|
||||||
|
|
||||||
for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
|
for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
|
||||||
if err := block.EncodeRLP(w); err != nil {
|
if err := block.EncodeRLP(w); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -331,7 +338,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash common.Hash, max uint64) (
|
||||||
parentHash := block.Header().ParentHash
|
parentHash := block.Header().ParentHash
|
||||||
block = self.GetBlock(parentHash)
|
block = self.GetBlock(parentHash)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
chainlogger.Infof("GetBlockHashesFromHash Parent UNKNOWN %x\n", parentHash)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -355,7 +361,7 @@ func (self *ChainManager) GetBlock(hash common.Hash) *types.Block {
|
||||||
}
|
}
|
||||||
var block types.StorageBlock
|
var block types.StorageBlock
|
||||||
if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
|
if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
|
||||||
chainlogger.Errorf("invalid block RLP for hash %x: %v", hash, err)
|
glog.V(logger.Error).Infof("invalid block RLP for hash %x: %v", hash, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return (*types.Block)(&block)
|
return (*types.Block)(&block)
|
||||||
|
|
@ -431,14 +437,28 @@ type queueEvent struct {
|
||||||
splitCount int
|
splitCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
func (self *ChainManager) procFutureBlocks() {
|
||||||
//self.tsmu.Lock()
|
blocks := make([]*types.Block, len(self.futureBlocks.blocks))
|
||||||
//defer self.tsmu.Unlock()
|
self.futureBlocks.Each(func(i int, block *types.Block) {
|
||||||
|
blocks[i] = block
|
||||||
|
})
|
||||||
|
|
||||||
|
types.BlockBy(types.Number).Sort(blocks)
|
||||||
|
self.InsertChain(blocks)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||||
// A queued approach to delivering events. This is generally faster than direct delivery and requires much less mutex acquiring.
|
// A queued approach to delivering events. This is generally faster than direct delivery and requires much less mutex acquiring.
|
||||||
var queue = make([]interface{}, len(chain))
|
var (
|
||||||
var queueEvent = queueEvent{queue: queue}
|
queue = make([]interface{}, len(chain))
|
||||||
|
queueEvent = queueEvent{queue: queue}
|
||||||
|
stats struct{ delayed, processed int }
|
||||||
|
tstart = time.Now()
|
||||||
|
)
|
||||||
for i, block := range chain {
|
for i, block := range chain {
|
||||||
|
if block == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
// Call in to the block processor and check for errors. It's likely that if one block fails
|
// Call in to the block processor and check for errors. It's likely that if one block fails
|
||||||
// all others will fail too (unless a known block is returned).
|
// all others will fail too (unless a known block is returned).
|
||||||
td, logs, err := self.processor.Process(block)
|
td, logs, err := self.processor.Process(block)
|
||||||
|
|
@ -447,15 +467,27 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == BlockEqualTSErr {
|
block.Td = new(big.Int)
|
||||||
queue[i] = ChainSideEvent{block, logs}
|
// Do not penelise on future block. We'll need a block queue eventually that will queue
|
||||||
|
// future block for future use
|
||||||
|
if err == BlockFutureErr {
|
||||||
|
self.futureBlocks.Push(block)
|
||||||
|
stats.delayed++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsParentErr(err) && self.futureBlocks.Has(block.ParentHash()) {
|
||||||
|
self.futureBlocks.Push(block)
|
||||||
|
stats.delayed++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
h := block.Header()
|
h := block.Header()
|
||||||
chainlogger.Errorf("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes()[:4])
|
|
||||||
chainlogger.Errorln(err)
|
glog.V(logger.Error).Infof("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes()[:4])
|
||||||
chainlogger.Debugln(block)
|
glog.V(logger.Error).Infoln(err)
|
||||||
|
glog.V(logger.Debug).Infoln(block)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
block.Td = td
|
block.Td = td
|
||||||
|
|
@ -472,7 +504,10 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||||
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, common.Big1)) < 0 {
|
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, common.Big1)) < 0 {
|
||||||
chash := cblock.Hash()
|
chash := cblock.Hash()
|
||||||
hash := block.Hash()
|
hash := block.Hash()
|
||||||
chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, hash[:4], td, cblock.Header().Number, chash[:4], self.td)
|
|
||||||
|
if glog.V(logger.Info) {
|
||||||
|
glog.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, hash[:4], td, cblock.Header().Number, chash[:4], self.td)
|
||||||
|
}
|
||||||
|
|
||||||
queue[i] = ChainSplitEvent{block, logs}
|
queue[i] = ChainSplitEvent{block, logs}
|
||||||
queueEvent.splitCount++
|
queueEvent.splitCount++
|
||||||
|
|
@ -493,6 +528,10 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||||
|
|
||||||
queue[i] = ChainEvent{block, logs}
|
queue[i] = ChainEvent{block, logs}
|
||||||
queueEvent.canonicalCount++
|
queueEvent.canonicalCount++
|
||||||
|
|
||||||
|
if glog.V(logger.Debug) {
|
||||||
|
glog.Infof("inserted block #%d (%d TXs %d UNCs) (%x...)\n", block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
queue[i] = ChainSideEvent{block, logs}
|
queue[i] = ChainSideEvent{block, logs}
|
||||||
queueEvent.sideCount++
|
queueEvent.sideCount++
|
||||||
|
|
@ -500,6 +539,16 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||||
}
|
}
|
||||||
self.mu.Unlock()
|
self.mu.Unlock()
|
||||||
|
|
||||||
|
stats.processed++
|
||||||
|
|
||||||
|
self.futureBlocks.Delete(block.Hash())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.delayed > 0 || stats.processed > 0) && bool(glog.V(logger.Info)) {
|
||||||
|
tend := time.Since(tstart)
|
||||||
|
start, end := chain[0], chain[len(chain)-1]
|
||||||
|
glog.Infof("imported %d block(s) %d delayed in %v. #%v [%x / %x]\n", stats.processed, stats.delayed, tend, end.Number(), start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
|
||||||
}
|
}
|
||||||
|
|
||||||
go self.eventMux.Post(queueEvent)
|
go self.eventMux.Post(queueEvent)
|
||||||
|
|
@ -509,7 +558,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||||
|
|
||||||
func (self *ChainManager) update() {
|
func (self *ChainManager) update() {
|
||||||
events := self.eventMux.Subscribe(queueEvent{})
|
events := self.eventMux.Subscribe(queueEvent{})
|
||||||
|
futureTimer := time.NewTicker(5 * time.Second)
|
||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
|
@ -535,6 +584,8 @@ out:
|
||||||
self.eventMux.Post(event)
|
self.eventMux.Post(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case <-futureTimer.C:
|
||||||
|
self.procFutureBlocks()
|
||||||
case <-self.quit:
|
case <-self.quit:
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ var ZeroHash160 = make([]byte, 20)
|
||||||
var ZeroHash512 = make([]byte, 64)
|
var ZeroHash512 = make([]byte, 64)
|
||||||
|
|
||||||
func GenesisBlock(db common.Database) *types.Block {
|
func GenesisBlock(db common.Database) *types.Block {
|
||||||
genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, params.GenesisDifficulty, 42, "")
|
genesis := types.NewBlock(common.Hash{}, common.Address{}, common.Hash{}, params.GenesisDifficulty, 42, nil)
|
||||||
genesis.Header().Number = common.Big0
|
genesis.Header().Number = common.Big0
|
||||||
genesis.Header().GasLimit = params.GenesisGasLimit
|
genesis.Header().GasLimit = params.GenesisGasLimit
|
||||||
genesis.Header().GasUsed = common.Big0
|
genesis.Header().GasUsed = common.Big0
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
@ -121,7 +123,10 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db common.Data
|
||||||
func (self *StateObject) MarkForDeletion() {
|
func (self *StateObject) MarkForDeletion() {
|
||||||
self.remove = true
|
self.remove = true
|
||||||
self.dirty = true
|
self.dirty = true
|
||||||
statelogger.Debugf("%x: #%d %v X\n", self.Address(), self.nonce, self.balance)
|
|
||||||
|
if glog.V(logger.Core) {
|
||||||
|
glog.Infof("%x: #%d %v X\n", self.Address(), self.nonce, self.balance)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) getAddr(addr common.Hash) *common.Value {
|
func (c *StateObject) getAddr(addr common.Hash) *common.Value {
|
||||||
|
|
@ -185,13 +190,17 @@ func (c *StateObject) GetInstr(pc *big.Int) *common.Value {
|
||||||
func (c *StateObject) AddBalance(amount *big.Int) {
|
func (c *StateObject) AddBalance(amount *big.Int) {
|
||||||
c.SetBalance(new(big.Int).Add(c.balance, amount))
|
c.SetBalance(new(big.Int).Add(c.balance, amount))
|
||||||
|
|
||||||
statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount)
|
if glog.V(logger.Core) {
|
||||||
|
glog.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.nonce, c.balance, amount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) SubBalance(amount *big.Int) {
|
func (c *StateObject) SubBalance(amount *big.Int) {
|
||||||
c.SetBalance(new(big.Int).Sub(c.balance, amount))
|
c.SetBalance(new(big.Int).Sub(c.balance, amount))
|
||||||
|
|
||||||
statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount)
|
if glog.V(logger.Core) {
|
||||||
|
glog.Infof("%x: #%d %v (- %v)\n", c.Address(), c.nonce, c.balance, amount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) SetBalance(amount *big.Int) {
|
func (c *StateObject) SetBalance(amount *big.Int) {
|
||||||
|
|
@ -225,7 +234,9 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error {
|
||||||
func (self *StateObject) SetGasPool(gasLimit *big.Int) {
|
func (self *StateObject) SetGasPool(gasLimit *big.Int) {
|
||||||
self.gasPool = new(big.Int).Set(gasLimit)
|
self.gasPool = new(big.Int).Set(gasLimit)
|
||||||
|
|
||||||
statelogger.Debugf("%x: gas (+ %v)", self.Address(), self.gasPool)
|
if glog.V(logger.Core) {
|
||||||
|
glog.Infof("%x: gas (+ %v)", self.Address(), self.gasPool)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) BuyGas(gas, price *big.Int) error {
|
func (self *StateObject) BuyGas(gas, price *big.Int) error {
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,10 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
var statelogger = logger.NewLogger("STATE")
|
|
||||||
|
|
||||||
// StateDBs within the ethereum protocol are used to store anything
|
// StateDBs within the ethereum protocol are used to store anything
|
||||||
// within the merkle trie. StateDBs take care of caching and storing
|
// within the merkle trie. StateDBs take care of caching and storing
|
||||||
// nested states. It's the general query interface to retrieve:
|
// nested states. It's the general query interface to retrieve:
|
||||||
|
|
@ -210,7 +209,9 @@ func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
|
||||||
|
|
||||||
// NewStateObject create a state object whether it exist in the trie or not
|
// NewStateObject create a state object whether it exist in the trie or not
|
||||||
func (self *StateDB) newStateObject(addr common.Address) *StateObject {
|
func (self *StateDB) newStateObject(addr common.Address) *StateObject {
|
||||||
statelogger.Debugf("(+) %x\n", addr)
|
if glog.V(logger.Core) {
|
||||||
|
glog.Infof("(+) %x\n", addr)
|
||||||
|
}
|
||||||
|
|
||||||
stateObject := NewStateObject(addr, self.db)
|
stateObject := NewStateObject(addr, self.db)
|
||||||
self.stateObjects[addr.Str()] = stateObject
|
self.stateObjects[addr.Str()] = stateObject
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -166,9 +168,6 @@ func (self *StateTransition) preCheck() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, err error) {
|
func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, err error) {
|
||||||
// statelogger.Debugf("(~) %x\n", self.msg.Hash())
|
|
||||||
|
|
||||||
// XXX Transactions after this point are considered valid.
|
|
||||||
if err = self.preCheck(); err != nil {
|
if err = self.preCheck(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +206,7 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
|
||||||
if err := self.UseGas(dataGas); err == nil {
|
if err := self.UseGas(dataGas); err == nil {
|
||||||
ref.SetCode(ret)
|
ref.SetCode(ret)
|
||||||
} else {
|
} else {
|
||||||
statelogger.Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas)
|
glog.V(logger.Core).Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,15 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// State query interface
|
// State query interface
|
||||||
|
|
@ -88,7 +89,10 @@ func TestRemoveInvalid(t *testing.T) {
|
||||||
|
|
||||||
func TestInvalidSender(t *testing.T) {
|
func TestInvalidSender(t *testing.T) {
|
||||||
pool, _ := setup()
|
pool, _ := setup()
|
||||||
err := pool.ValidateTransaction(new(types.Transaction))
|
tx := new(types.Transaction)
|
||||||
|
tx.R = new(big.Int)
|
||||||
|
tx.S = new(big.Int)
|
||||||
|
err := pool.ValidateTransaction(tx)
|
||||||
if err != ErrInvalidSender {
|
if err != ErrInvalidSender {
|
||||||
t.Errorf("expected %v, got %v", ErrInvalidSender, err)
|
t.Errorf("expected %v, got %v", ErrInvalidSender, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ type Header struct {
|
||||||
// Creation time
|
// Creation time
|
||||||
Time uint64
|
Time uint64
|
||||||
// Extra data
|
// Extra data
|
||||||
Extra string
|
Extra []byte
|
||||||
// Mix digest for quick checking to prevent DOS
|
// Mix digest for quick checking to prevent DOS
|
||||||
MixDigest common.Hash
|
MixDigest common.Hash
|
||||||
// Nonce
|
// Nonce
|
||||||
|
|
@ -121,7 +121,7 @@ type storageblock struct {
|
||||||
TD *big.Int
|
TD *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra string) *Block {
|
func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra []byte) *Block {
|
||||||
header := &Header{
|
header := &Header{
|
||||||
Root: root,
|
Root: root,
|
||||||
ParentHash: parentHash,
|
ParentHash: parentHash,
|
||||||
|
|
@ -371,7 +371,7 @@ func (self *Header) String() string {
|
||||||
GasLimit: %v
|
GasLimit: %v
|
||||||
GasUsed: %v
|
GasUsed: %v
|
||||||
Time: %v
|
Time: %v
|
||||||
Extra: %v
|
Extra: %s
|
||||||
MixDigest: %x
|
MixDigest: %x
|
||||||
Nonce: %x`,
|
Nonce: %x`,
|
||||||
self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.MixDigest, self.Nonce)
|
self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.MixDigest, self.Nonce)
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@ func TestBlockEncoding(t *testing.T) {
|
||||||
GasLimit: big.NewInt(50000),
|
GasLimit: big.NewInt(50000),
|
||||||
AccountNonce: 0,
|
AccountNonce: 0,
|
||||||
V: 27,
|
V: 27,
|
||||||
R: common.FromHex("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f"),
|
R: common.String2Big("0x9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f"),
|
||||||
S: common.FromHex("8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1"),
|
S: common.String2Big("0x8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1"),
|
||||||
Recipient: &to,
|
Recipient: &to,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -24,15 +24,31 @@ type Transaction struct {
|
||||||
Amount *big.Int
|
Amount *big.Int
|
||||||
Payload []byte
|
Payload []byte
|
||||||
V byte
|
V byte
|
||||||
R, S []byte
|
R, S *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContractCreationTx(amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
func NewContractCreationTx(amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
||||||
return &Transaction{Recipient: nil, Amount: amount, GasLimit: gasLimit, Price: gasPrice, Payload: data}
|
return &Transaction{
|
||||||
|
Recipient: nil,
|
||||||
|
Amount: amount,
|
||||||
|
GasLimit: gasLimit,
|
||||||
|
Price: gasPrice,
|
||||||
|
Payload: data,
|
||||||
|
R: new(big.Int),
|
||||||
|
S: new(big.Int),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransactionMessage(to common.Address, amount, gasAmount, gasPrice *big.Int, data []byte) *Transaction {
|
func NewTransactionMessage(to common.Address, amount, gasAmount, gasPrice *big.Int, data []byte) *Transaction {
|
||||||
return &Transaction{Recipient: &to, Amount: amount, GasLimit: gasAmount, Price: gasPrice, Payload: data}
|
return &Transaction{
|
||||||
|
Recipient: &to,
|
||||||
|
Amount: amount,
|
||||||
|
GasLimit: gasAmount,
|
||||||
|
Price: gasPrice,
|
||||||
|
Payload: data,
|
||||||
|
R: new(big.Int),
|
||||||
|
S: new(big.Int),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransactionFromBytes(data []byte) *Transaction {
|
func NewTransactionFromBytes(data []byte) *Transaction {
|
||||||
|
|
@ -94,8 +110,8 @@ func (tx *Transaction) To() *common.Address {
|
||||||
|
|
||||||
func (tx *Transaction) Curve() (v byte, r []byte, s []byte) {
|
func (tx *Transaction) Curve() (v byte, r []byte, s []byte) {
|
||||||
v = byte(tx.V)
|
v = byte(tx.V)
|
||||||
r = common.LeftPadBytes(tx.R, 32)
|
r = common.LeftPadBytes(tx.R.Bytes(), 32)
|
||||||
s = common.LeftPadBytes(tx.S, 32)
|
s = common.LeftPadBytes(tx.S.Bytes(), 32)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,8 +134,8 @@ func (tx *Transaction) PublicKey() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) SetSignatureValues(sig []byte) error {
|
func (tx *Transaction) SetSignatureValues(sig []byte) error {
|
||||||
tx.R = sig[:32]
|
tx.R = common.Bytes2Big(sig[:32])
|
||||||
tx.S = sig[32:64]
|
tx.S = common.Bytes2Big(sig[32:64])
|
||||||
tx.V = sig[64] + 27
|
tx.V = sig[64] + 27
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +153,7 @@ func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) error {
|
||||||
// TODO: remove
|
// TODO: remove
|
||||||
func (tx *Transaction) RlpData() interface{} {
|
func (tx *Transaction) RlpData() interface{} {
|
||||||
data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
|
data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
|
||||||
return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes())
|
return append(data, tx.V, tx.R.Bytes(), tx.S.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) String() string {
|
func (tx *Transaction) String() string {
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ var (
|
||||||
Amount: big.NewInt(10),
|
Amount: big.NewInt(10),
|
||||||
Payload: common.FromHex("5544"),
|
Payload: common.FromHex("5544"),
|
||||||
V: 28,
|
V: 28,
|
||||||
R: common.FromHex("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a"),
|
R: common.String2Big("0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a"),
|
||||||
S: common.FromHex("8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"),
|
S: common.String2Big("0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,9 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
var vmlogger = logger.NewLogger("VM")
|
|
||||||
|
|
||||||
// Global Debug flag indicating Debug VM (full logging)
|
// Global Debug flag indicating Debug VM (full logging)
|
||||||
var Debug bool
|
var Debug bool
|
||||||
|
|
||||||
|
|
@ -41,7 +39,7 @@ func NewVm(env Environment) VirtualMachine {
|
||||||
case JitVmTy:
|
case JitVmTy:
|
||||||
return NewJitVm(env)
|
return NewJitVm(env)
|
||||||
default:
|
default:
|
||||||
vmlogger.Infoln("unsupported vm type %d", env.VmType())
|
glog.V(0).Infoln("unsupported vm type %d", env.VmType())
|
||||||
fallthrough
|
fallthrough
|
||||||
case StdVmTy:
|
case StdVmTy:
|
||||||
return New(env)
|
return New(env)
|
||||||
|
|
|
||||||
126
core/vm/gas.go
126
core/vm/gas.go
|
|
@ -38,7 +38,7 @@ func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.stackPush && len(stack.data)-r.stackPop > int(params.StackLimit.Int64()) {
|
if r.stackPush > 0 && len(stack.data)-r.stackPop+r.stackPush > int(params.StackLimit.Int64())+1 {
|
||||||
return fmt.Errorf("stack limit reached %d (%d)", len(stack.data), params.StackLimit.Int64())
|
return fmt.Errorf("stack limit reached %d (%d)", len(stack.data), params.StackLimit.Int64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,70 +57,70 @@ func toWordSize(size *big.Int) *big.Int {
|
||||||
type req struct {
|
type req struct {
|
||||||
stackPop int
|
stackPop int
|
||||||
gas *big.Int
|
gas *big.Int
|
||||||
stackPush bool
|
stackPush int
|
||||||
}
|
}
|
||||||
|
|
||||||
var _baseCheck = map[OpCode]req{
|
var _baseCheck = map[OpCode]req{
|
||||||
// opcode | stack pop | gas price | stack push
|
// opcode | stack pop | gas price | stack push
|
||||||
ADD: {2, GasFastestStep, true},
|
ADD: {2, GasFastestStep, 1},
|
||||||
LT: {2, GasFastestStep, true},
|
LT: {2, GasFastestStep, 1},
|
||||||
GT: {2, GasFastestStep, true},
|
GT: {2, GasFastestStep, 1},
|
||||||
SLT: {2, GasFastestStep, true},
|
SLT: {2, GasFastestStep, 1},
|
||||||
SGT: {2, GasFastestStep, true},
|
SGT: {2, GasFastestStep, 1},
|
||||||
EQ: {2, GasFastestStep, true},
|
EQ: {2, GasFastestStep, 1},
|
||||||
ISZERO: {1, GasFastestStep, true},
|
ISZERO: {1, GasFastestStep, 1},
|
||||||
SUB: {2, GasFastestStep, true},
|
SUB: {2, GasFastestStep, 1},
|
||||||
AND: {2, GasFastestStep, true},
|
AND: {2, GasFastestStep, 1},
|
||||||
OR: {2, GasFastestStep, true},
|
OR: {2, GasFastestStep, 1},
|
||||||
XOR: {2, GasFastestStep, true},
|
XOR: {2, GasFastestStep, 1},
|
||||||
NOT: {1, GasFastestStep, true},
|
NOT: {1, GasFastestStep, 1},
|
||||||
BYTE: {2, GasFastestStep, true},
|
BYTE: {2, GasFastestStep, 1},
|
||||||
CALLDATALOAD: {1, GasFastestStep, true},
|
CALLDATALOAD: {1, GasFastestStep, 1},
|
||||||
CALLDATACOPY: {3, GasFastestStep, true},
|
CALLDATACOPY: {3, GasFastestStep, 1},
|
||||||
MLOAD: {1, GasFastestStep, true},
|
MLOAD: {1, GasFastestStep, 1},
|
||||||
MSTORE: {2, GasFastestStep, false},
|
MSTORE: {2, GasFastestStep, 0},
|
||||||
MSTORE8: {2, GasFastestStep, false},
|
MSTORE8: {2, GasFastestStep, 0},
|
||||||
CODECOPY: {3, GasFastestStep, false},
|
CODECOPY: {3, GasFastestStep, 0},
|
||||||
MUL: {2, GasFastStep, true},
|
MUL: {2, GasFastStep, 1},
|
||||||
DIV: {2, GasFastStep, true},
|
DIV: {2, GasFastStep, 1},
|
||||||
SDIV: {2, GasFastStep, true},
|
SDIV: {2, GasFastStep, 1},
|
||||||
MOD: {2, GasFastStep, true},
|
MOD: {2, GasFastStep, 1},
|
||||||
SMOD: {2, GasFastStep, true},
|
SMOD: {2, GasFastStep, 1},
|
||||||
SIGNEXTEND: {2, GasFastStep, true},
|
SIGNEXTEND: {2, GasFastStep, 1},
|
||||||
ADDMOD: {3, GasMidStep, true},
|
ADDMOD: {3, GasMidStep, 1},
|
||||||
MULMOD: {3, GasMidStep, true},
|
MULMOD: {3, GasMidStep, 1},
|
||||||
JUMP: {1, GasMidStep, false},
|
JUMP: {1, GasMidStep, 0},
|
||||||
JUMPI: {2, GasSlowStep, false},
|
JUMPI: {2, GasSlowStep, 0},
|
||||||
EXP: {2, GasSlowStep, true},
|
EXP: {2, GasSlowStep, 1},
|
||||||
ADDRESS: {0, GasQuickStep, true},
|
ADDRESS: {0, GasQuickStep, 1},
|
||||||
ORIGIN: {0, GasQuickStep, true},
|
ORIGIN: {0, GasQuickStep, 1},
|
||||||
CALLER: {0, GasQuickStep, true},
|
CALLER: {0, GasQuickStep, 1},
|
||||||
CALLVALUE: {0, GasQuickStep, true},
|
CALLVALUE: {0, GasQuickStep, 1},
|
||||||
CODESIZE: {0, GasQuickStep, true},
|
CODESIZE: {0, GasQuickStep, 1},
|
||||||
GASPRICE: {0, GasQuickStep, true},
|
GASPRICE: {0, GasQuickStep, 1},
|
||||||
COINBASE: {0, GasQuickStep, true},
|
COINBASE: {0, GasQuickStep, 1},
|
||||||
TIMESTAMP: {0, GasQuickStep, true},
|
TIMESTAMP: {0, GasQuickStep, 1},
|
||||||
NUMBER: {0, GasQuickStep, true},
|
NUMBER: {0, GasQuickStep, 1},
|
||||||
CALLDATASIZE: {0, GasQuickStep, true},
|
CALLDATASIZE: {0, GasQuickStep, 1},
|
||||||
DIFFICULTY: {0, GasQuickStep, true},
|
DIFFICULTY: {0, GasQuickStep, 1},
|
||||||
GASLIMIT: {0, GasQuickStep, true},
|
GASLIMIT: {0, GasQuickStep, 1},
|
||||||
POP: {1, GasQuickStep, false},
|
POP: {1, GasQuickStep, 0},
|
||||||
PC: {0, GasQuickStep, true},
|
PC: {0, GasQuickStep, 1},
|
||||||
MSIZE: {0, GasQuickStep, true},
|
MSIZE: {0, GasQuickStep, 1},
|
||||||
GAS: {0, GasQuickStep, true},
|
GAS: {0, GasQuickStep, 1},
|
||||||
BLOCKHASH: {1, GasExtStep, true},
|
BLOCKHASH: {1, GasExtStep, 1},
|
||||||
BALANCE: {1, GasExtStep, true},
|
BALANCE: {1, GasExtStep, 1},
|
||||||
EXTCODESIZE: {1, GasExtStep, true},
|
EXTCODESIZE: {1, GasExtStep, 1},
|
||||||
EXTCODECOPY: {4, GasExtStep, false},
|
EXTCODECOPY: {4, GasExtStep, 0},
|
||||||
SLOAD: {1, params.SloadGas, true},
|
SLOAD: {1, params.SloadGas, 1},
|
||||||
SSTORE: {2, Zero, false},
|
SSTORE: {2, Zero, 0},
|
||||||
SHA3: {2, params.Sha3Gas, true},
|
SHA3: {2, params.Sha3Gas, 1},
|
||||||
CREATE: {3, params.CreateGas, true},
|
CREATE: {3, params.CreateGas, 1},
|
||||||
CALL: {7, params.CallGas, true},
|
CALL: {7, params.CallGas, 1},
|
||||||
CALLCODE: {7, params.CallGas, true},
|
CALLCODE: {7, params.CallGas, 1},
|
||||||
JUMPDEST: {0, params.JumpdestGas, false},
|
JUMPDEST: {0, params.JumpdestGas, 0},
|
||||||
SUICIDE: {1, Zero, false},
|
SUICIDE: {1, Zero, 0},
|
||||||
RETURN: {2, Zero, false},
|
RETURN: {2, Zero, 0},
|
||||||
PUSH1: {0, GasFastestStep, true},
|
PUSH1: {0, GasFastestStep, 1},
|
||||||
DUP1: {0, Zero, true},
|
DUP1: {0, Zero, 1},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -885,21 +886,17 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *
|
||||||
|
|
||||||
func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
|
func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
|
||||||
if self.debug {
|
if self.debug {
|
||||||
if self.logTy == LogTyPretty {
|
|
||||||
self.logStr += fmt.Sprintf(format, v...)
|
self.logStr += fmt.Sprintf(format, v...)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) Endl() VirtualMachine {
|
func (self *Vm) Endl() VirtualMachine {
|
||||||
if self.debug {
|
if self.debug {
|
||||||
if self.logTy == LogTyPretty {
|
glog.V(0).Infoln(self.logStr)
|
||||||
vmlogger.Infoln(self.logStr)
|
|
||||||
self.logStr = ""
|
self.logStr = ""
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ func (s *Ethereum) PeersInfo() (peersinfo []*PeerInfo) {
|
||||||
|
|
||||||
func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
|
func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
|
||||||
s.chainManager.ResetWithGenesisBlock(gb)
|
s.chainManager.ResetWithGenesisBlock(gb)
|
||||||
s.pow.UpdateCache(true)
|
s.pow.UpdateCache(0, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) StartMining() error {
|
func (s *Ethereum) StartMining() error {
|
||||||
|
|
|
||||||
|
|
@ -349,7 +349,7 @@ func (self *ethProtocol) handleStatus() error {
|
||||||
return self.protoError(ErrSuspendedPeer, "")
|
return self.protoError(ErrSuspendedPeer, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4])
|
self.peer.Debugf("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4])
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,13 @@ package jsre
|
||||||
|
|
||||||
const pp_js = `
|
const pp_js = `
|
||||||
function pp(object, indent) {
|
function pp(object, indent) {
|
||||||
var str = "";
|
|
||||||
/*
|
|
||||||
var o = object;
|
|
||||||
try {
|
try {
|
||||||
object = JSON.stringify(object)
|
JSON.stringify(object)
|
||||||
object = JSON.parse(object);
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
object = o;
|
return pp(e, indent);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
var str = "";
|
||||||
if(object instanceof Array) {
|
if(object instanceof Array) {
|
||||||
str += "[";
|
str += "[";
|
||||||
for(var i = 0, l = object.length; i < l; i++) {
|
for(var i = 0, l = object.length; i < l; i++) {
|
||||||
|
|
@ -24,7 +20,7 @@ function pp(object, indent) {
|
||||||
}
|
}
|
||||||
str += " ]";
|
str += " ]";
|
||||||
} else if (object instanceof Error) {
|
} else if (object instanceof Error) {
|
||||||
str += "\033[31m" + "Error";
|
str += "\033[31m" + "Error:\033[0m " + object.message;
|
||||||
} else if (isBigNumber(object)) {
|
} else if (isBigNumber(object)) {
|
||||||
str += "\033[32m'" + object.toString(10) + "'";
|
str += "\033[32m'" + object.toString(10) + "'";
|
||||||
} else if(typeof(object) === "object") {
|
} else if(typeof(object) === "object") {
|
||||||
|
|
|
||||||
191
logger/glog/LICENSE
Normal file
191
logger/glog/LICENSE
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, and
|
||||||
|
distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||||
|
owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||||
|
that control, are controlled by, or are under common control with that entity.
|
||||||
|
For the purposes of this definition, "control" means (i) the power, direct or
|
||||||
|
indirect, to cause the direction or management of such entity, whether by
|
||||||
|
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||||
|
permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, including
|
||||||
|
but not limited to software source code, documentation source, and configuration
|
||||||
|
files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical transformation or
|
||||||
|
translation of a Source form, including but not limited to compiled object code,
|
||||||
|
generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||||
|
available under the License, as indicated by a copyright notice that is included
|
||||||
|
in or attached to the work (an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||||
|
is based on (or derived from) the Work and for which the editorial revisions,
|
||||||
|
annotations, elaborations, or other modifications represent, as a whole, an
|
||||||
|
original work of authorship. For the purposes of this License, Derivative Works
|
||||||
|
shall not include works that remain separable from, or merely link (or bind by
|
||||||
|
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including the original version
|
||||||
|
of the Work and any modifications or additions to that Work or Derivative Works
|
||||||
|
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||||
|
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||||
|
on behalf of the copyright owner. For the purposes of this definition,
|
||||||
|
"submitted" means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems, and
|
||||||
|
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||||
|
the purpose of discussing and improving the Work, but excluding communication
|
||||||
|
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||||
|
owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||||
|
of whom a Contribution has been received by Licensor and subsequently
|
||||||
|
incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License.
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby
|
||||||
|
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||||
|
Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License.
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby
|
||||||
|
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable (except as stated in this section) patent license to make, have
|
||||||
|
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||||
|
such license applies only to those patent claims licensable by such Contributor
|
||||||
|
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||||
|
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||||
|
submitted. If You institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||||
|
Contribution incorporated within the Work constitutes direct or contributory
|
||||||
|
patent infringement, then any patent licenses granted to You under this License
|
||||||
|
for that Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution.
|
||||||
|
|
||||||
|
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||||
|
in any medium, with or without modifications, and in Source or Object form,
|
||||||
|
provided that You meet the following conditions:
|
||||||
|
|
||||||
|
You must give any other recipients of the Work or Derivative Works a copy of
|
||||||
|
this License; and
|
||||||
|
You must cause any modified files to carry prominent notices stating that You
|
||||||
|
changed the files; and
|
||||||
|
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||||
|
all copyright, patent, trademark, and attribution notices from the Source form
|
||||||
|
of the Work, excluding those notices that do not pertain to any part of the
|
||||||
|
Derivative Works; and
|
||||||
|
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||||
|
Derivative Works that You distribute must include a readable copy of the
|
||||||
|
attribution notices contained within such NOTICE file, excluding those notices
|
||||||
|
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||||
|
following places: within a NOTICE text file distributed as part of the
|
||||||
|
Derivative Works; within the Source form or documentation, if provided along
|
||||||
|
with the Derivative Works; or, within a display generated by the Derivative
|
||||||
|
Works, if and wherever such third-party notices normally appear. The contents of
|
||||||
|
the NOTICE file are for informational purposes only and do not modify the
|
||||||
|
License. You may add Your own attribution notices within Derivative Works that
|
||||||
|
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||||
|
provided that such additional attribution notices cannot be construed as
|
||||||
|
modifying the License.
|
||||||
|
You may add Your own copyright statement to Your modifications and may provide
|
||||||
|
additional or different license terms and conditions for use, reproduction, or
|
||||||
|
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||||
|
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||||
|
with the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions.
|
||||||
|
|
||||||
|
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||||
|
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||||
|
conditions of this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||||
|
any separate license agreement you may have executed with Licensor regarding
|
||||||
|
such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks.
|
||||||
|
|
||||||
|
This License does not grant permission to use the trade names, trademarks,
|
||||||
|
service marks, or product names of the Licensor, except as required for
|
||||||
|
reasonable and customary use in describing the origin of the Work and
|
||||||
|
reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||||
|
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||||
|
including, without limitation, any warranties or conditions of TITLE,
|
||||||
|
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||||
|
solely responsible for determining the appropriateness of using or
|
||||||
|
redistributing the Work and assume any risks associated with Your exercise of
|
||||||
|
permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability.
|
||||||
|
|
||||||
|
In no event and under no legal theory, whether in tort (including negligence),
|
||||||
|
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||||
|
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special, incidental,
|
||||||
|
or consequential damages of any character arising as a result of this License or
|
||||||
|
out of the use or inability to use the Work (including but not limited to
|
||||||
|
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||||
|
any and all other commercial damages or losses), even if such Contributor has
|
||||||
|
been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability.
|
||||||
|
|
||||||
|
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||||
|
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||||
|
other liability obligations and/or rights consistent with this License. However,
|
||||||
|
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||||
|
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||||
|
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason of your
|
||||||
|
accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following boilerplate
|
||||||
|
notice, with the fields enclosed by brackets "[]" replaced with your own
|
||||||
|
identifying information. (Don't include the brackets!) The text should be
|
||||||
|
enclosed in the appropriate comment syntax for the file format. We also
|
||||||
|
recommend that a file or class name and description of purpose be included on
|
||||||
|
the same "printed page" as the copyright notice for easier identification within
|
||||||
|
third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
44
logger/glog/README
Normal file
44
logger/glog/README
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
glog
|
||||||
|
====
|
||||||
|
|
||||||
|
Leveled execution logs for Go.
|
||||||
|
|
||||||
|
This is an efficient pure Go implementation of leveled logs in the
|
||||||
|
manner of the open source C++ package
|
||||||
|
http://code.google.com/p/google-glog
|
||||||
|
|
||||||
|
By binding methods to booleans it is possible to use the log package
|
||||||
|
without paying the expense of evaluating the arguments to the log.
|
||||||
|
Through the -vmodule flag, the package also provides fine-grained
|
||||||
|
control over logging at the file level.
|
||||||
|
|
||||||
|
The comment from glog.go introduces the ideas:
|
||||||
|
|
||||||
|
Package glog implements logging analogous to the Google-internal
|
||||||
|
C++ INFO/ERROR/V setup. It provides functions Info, Warning,
|
||||||
|
Error, Fatal, plus formatting variants such as Infof. It
|
||||||
|
also provides V-style logging controlled by the -v and
|
||||||
|
-vmodule=file=2 flags.
|
||||||
|
|
||||||
|
Basic examples:
|
||||||
|
|
||||||
|
glog.Info("Prepare to repel boarders")
|
||||||
|
|
||||||
|
glog.Fatalf("Initialization failed: %s", err)
|
||||||
|
|
||||||
|
See the documentation for the V function for an explanation
|
||||||
|
of these examples:
|
||||||
|
|
||||||
|
if glog.V(2) {
|
||||||
|
glog.Info("Starting transaction...")
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(2).Infoln("Processed", nItems, "elements")
|
||||||
|
|
||||||
|
|
||||||
|
The repository contains an open source version of the log package
|
||||||
|
used inside Google. The master copy of the source lives inside
|
||||||
|
Google, not here. The code in this repo is for export only and is not itself
|
||||||
|
under development. Feature requests will be ignored.
|
||||||
|
|
||||||
|
Send bug reports to golang-nuts@googlegroups.com.
|
||||||
1191
logger/glog/glog.go
Normal file
1191
logger/glog/glog.go
Normal file
File diff suppressed because it is too large
Load diff
124
logger/glog/glog_file.go
Normal file
124
logger/glog/glog_file.go
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
|
||||||
|
//
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// File I/O for logs.
|
||||||
|
|
||||||
|
package glog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaxSize is the maximum size of a log file in bytes.
|
||||||
|
var MaxSize uint64 = 1024 * 1024 * 1800
|
||||||
|
|
||||||
|
// logDirs lists the candidate directories for new log files.
|
||||||
|
var logDirs []string
|
||||||
|
|
||||||
|
// If non-empty, overrides the choice of directory in which to write logs.
|
||||||
|
// See createLogDirs for the full list of possible destinations.
|
||||||
|
//var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory")
|
||||||
|
var logDir *string = new(string)
|
||||||
|
|
||||||
|
func createLogDirs() {
|
||||||
|
if *logDir != "" {
|
||||||
|
logDirs = append(logDirs, *logDir)
|
||||||
|
}
|
||||||
|
logDirs = append(logDirs, os.TempDir())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pid = os.Getpid()
|
||||||
|
program = filepath.Base(os.Args[0])
|
||||||
|
host = "unknownhost"
|
||||||
|
userName = "unknownuser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
h, err := os.Hostname()
|
||||||
|
if err == nil {
|
||||||
|
host = shortHostname(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
current, err := user.Current()
|
||||||
|
if err == nil {
|
||||||
|
userName = current.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize userName since it may contain filepath separators on Windows.
|
||||||
|
userName = strings.Replace(userName, `\`, "_", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// shortHostname returns its argument, truncating at the first period.
|
||||||
|
// For instance, given "www.google.com" it returns "www".
|
||||||
|
func shortHostname(hostname string) string {
|
||||||
|
if i := strings.Index(hostname, "."); i >= 0 {
|
||||||
|
return hostname[:i]
|
||||||
|
}
|
||||||
|
return hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
// logName returns a new log file name containing tag, with start time t, and
|
||||||
|
// the name for the symlink for tag.
|
||||||
|
func logName(tag string, t time.Time) (name, link string) {
|
||||||
|
name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
|
||||||
|
program,
|
||||||
|
host,
|
||||||
|
userName,
|
||||||
|
tag,
|
||||||
|
t.Year(),
|
||||||
|
t.Month(),
|
||||||
|
t.Day(),
|
||||||
|
t.Hour(),
|
||||||
|
t.Minute(),
|
||||||
|
t.Second(),
|
||||||
|
pid)
|
||||||
|
return name, program + "." + tag
|
||||||
|
}
|
||||||
|
|
||||||
|
var onceLogDirs sync.Once
|
||||||
|
|
||||||
|
// create creates a new log file and returns the file and its filename, which
|
||||||
|
// contains tag ("INFO", "FATAL", etc.) and t. If the file is created
|
||||||
|
// successfully, create also attempts to update the symlink for that tag, ignoring
|
||||||
|
// errors.
|
||||||
|
func create(tag string, t time.Time) (f *os.File, filename string, err error) {
|
||||||
|
onceLogDirs.Do(createLogDirs)
|
||||||
|
if len(logDirs) == 0 {
|
||||||
|
return nil, "", errors.New("log: no log dirs")
|
||||||
|
}
|
||||||
|
name, link := logName(tag, t)
|
||||||
|
var lastErr error
|
||||||
|
for _, dir := range logDirs {
|
||||||
|
fname := filepath.Join(dir, name)
|
||||||
|
f, err := os.Create(fname)
|
||||||
|
if err == nil {
|
||||||
|
symlink := filepath.Join(dir, link)
|
||||||
|
os.Remove(symlink) // ignore err
|
||||||
|
os.Symlink(name, symlink) // ignore err
|
||||||
|
return f, fname, nil
|
||||||
|
}
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
|
||||||
|
}
|
||||||
415
logger/glog/glog_test.go
Normal file
415
logger/glog/glog_test.go
Normal file
|
|
@ -0,0 +1,415 @@
|
||||||
|
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
|
||||||
|
//
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package glog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
stdLog "log"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test that shortHostname works as advertised.
|
||||||
|
func TestShortHostname(t *testing.T) {
|
||||||
|
for hostname, expect := range map[string]string{
|
||||||
|
"": "",
|
||||||
|
"host": "host",
|
||||||
|
"host.google.com": "host",
|
||||||
|
} {
|
||||||
|
if got := shortHostname(hostname); expect != got {
|
||||||
|
t.Errorf("shortHostname(%q): expected %q, got %q", hostname, expect, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// flushBuffer wraps a bytes.Buffer to satisfy flushSyncWriter.
|
||||||
|
type flushBuffer struct {
|
||||||
|
bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *flushBuffer) Flush() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *flushBuffer) Sync() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap sets the log writers and returns the old array.
|
||||||
|
func (l *loggingT) swap(writers [numSeverity]flushSyncWriter) (old [numSeverity]flushSyncWriter) {
|
||||||
|
l.mu.Lock()
|
||||||
|
defer l.mu.Unlock()
|
||||||
|
old = l.file
|
||||||
|
for i, w := range writers {
|
||||||
|
logging.file[i] = w
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// newBuffers sets the log writers to all new byte buffers and returns the old array.
|
||||||
|
func (l *loggingT) newBuffers() [numSeverity]flushSyncWriter {
|
||||||
|
return l.swap([numSeverity]flushSyncWriter{new(flushBuffer), new(flushBuffer), new(flushBuffer), new(flushBuffer)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// contents returns the specified log value as a string.
|
||||||
|
func contents(s severity) string {
|
||||||
|
return logging.file[s].(*flushBuffer).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// contains reports whether the string is contained in the log.
|
||||||
|
func contains(s severity, str string, t *testing.T) bool {
|
||||||
|
return strings.Contains(contents(s), str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setFlags configures the logging flags how the test expects them.
|
||||||
|
func setFlags() {
|
||||||
|
logging.toStderr = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that Info works as advertised.
|
||||||
|
func TestInfo(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
Info("test")
|
||||||
|
if !contains(infoLog, "I", t) {
|
||||||
|
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
||||||
|
}
|
||||||
|
if !contains(infoLog, "test", t) {
|
||||||
|
t.Error("Info failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfoDepth(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
|
||||||
|
f := func() { InfoDepth(1, "depth-test1") }
|
||||||
|
|
||||||
|
// The next three lines must stay together
|
||||||
|
_, _, wantLine, _ := runtime.Caller(0)
|
||||||
|
InfoDepth(0, "depth-test0")
|
||||||
|
f()
|
||||||
|
|
||||||
|
msgs := strings.Split(strings.TrimSuffix(contents(infoLog), "\n"), "\n")
|
||||||
|
if len(msgs) != 2 {
|
||||||
|
t.Fatalf("Got %d lines, expected 2", len(msgs))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, m := range msgs {
|
||||||
|
if !strings.HasPrefix(m, "I") {
|
||||||
|
t.Errorf("InfoDepth[%d] has wrong character: %q", i, m)
|
||||||
|
}
|
||||||
|
w := fmt.Sprintf("depth-test%d", i)
|
||||||
|
if !strings.Contains(m, w) {
|
||||||
|
t.Errorf("InfoDepth[%d] missing %q: %q", i, w, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull out the line number (between : and ])
|
||||||
|
msg := m[strings.LastIndex(m, ":")+1:]
|
||||||
|
x := strings.Index(msg, "]")
|
||||||
|
if x < 0 {
|
||||||
|
t.Errorf("InfoDepth[%d]: missing ']': %q", i, m)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
line, err := strconv.Atoi(msg[:x])
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("InfoDepth[%d]: bad line number: %q", i, m)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wantLine++
|
||||||
|
if wantLine != line {
|
||||||
|
t.Errorf("InfoDepth[%d]: got line %d, want %d", i, line, wantLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
CopyStandardLogTo("INFO")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that CopyStandardLogTo panics on bad input.
|
||||||
|
func TestCopyStandardLogToPanic(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if s, ok := recover().(string); !ok || !strings.Contains(s, "LOG") {
|
||||||
|
t.Errorf(`CopyStandardLogTo("LOG") should have panicked: %v`, s)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
CopyStandardLogTo("LOG")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that using the standard log package logs to INFO.
|
||||||
|
func TestStandardLog(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
stdLog.Print("test")
|
||||||
|
if !contains(infoLog, "I", t) {
|
||||||
|
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
||||||
|
}
|
||||||
|
if !contains(infoLog, "test", t) {
|
||||||
|
t.Error("Info failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the header has the correct format.
|
||||||
|
func TestHeader(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
defer func(previous func() time.Time) { timeNow = previous }(timeNow)
|
||||||
|
timeNow = func() time.Time {
|
||||||
|
return time.Date(2006, 1, 2, 15, 4, 5, .067890e9, time.Local)
|
||||||
|
}
|
||||||
|
pid = 1234
|
||||||
|
Info("test")
|
||||||
|
var line int
|
||||||
|
format := "I0102 15:04:05.067890 1234 glog_test.go:%d] test\n"
|
||||||
|
n, err := fmt.Sscanf(contents(infoLog), format, &line)
|
||||||
|
if n != 1 || err != nil {
|
||||||
|
t.Errorf("log format error: %d elements, error %s:\n%s", n, err, contents(infoLog))
|
||||||
|
}
|
||||||
|
// Scanf treats multiple spaces as equivalent to a single space,
|
||||||
|
// so check for correct space-padding also.
|
||||||
|
want := fmt.Sprintf(format, line)
|
||||||
|
if contents(infoLog) != want {
|
||||||
|
t.Errorf("log format error: got:\n\t%q\nwant:\t%q", contents(infoLog), want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an Error log goes to Warning and Info.
|
||||||
|
// Even in the Info log, the source character will be E, so the data should
|
||||||
|
// all be identical.
|
||||||
|
func TestError(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
Error("test")
|
||||||
|
if !contains(errorLog, "E", t) {
|
||||||
|
t.Errorf("Error has wrong character: %q", contents(errorLog))
|
||||||
|
}
|
||||||
|
if !contains(errorLog, "test", t) {
|
||||||
|
t.Error("Error failed")
|
||||||
|
}
|
||||||
|
str := contents(errorLog)
|
||||||
|
if !contains(warningLog, str, t) {
|
||||||
|
t.Error("Warning failed")
|
||||||
|
}
|
||||||
|
if !contains(infoLog, str, t) {
|
||||||
|
t.Error("Info failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a Warning log goes to Info.
|
||||||
|
// Even in the Info log, the source character will be W, so the data should
|
||||||
|
// all be identical.
|
||||||
|
func TestWarning(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
Warning("test")
|
||||||
|
if !contains(warningLog, "W", t) {
|
||||||
|
t.Errorf("Warning has wrong character: %q", contents(warningLog))
|
||||||
|
}
|
||||||
|
if !contains(warningLog, "test", t) {
|
||||||
|
t.Error("Warning failed")
|
||||||
|
}
|
||||||
|
str := contents(warningLog)
|
||||||
|
if !contains(infoLog, str, t) {
|
||||||
|
t.Error("Info failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a V log goes to Info.
|
||||||
|
func TestV(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
logging.verbosity.Set("2")
|
||||||
|
defer logging.verbosity.Set("0")
|
||||||
|
V(2).Info("test")
|
||||||
|
if !contains(infoLog, "I", t) {
|
||||||
|
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
||||||
|
}
|
||||||
|
if !contains(infoLog, "test", t) {
|
||||||
|
t.Error("Info failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a vmodule enables a log in this file.
|
||||||
|
func TestVmoduleOn(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
logging.vmodule.Set("glog_test=2")
|
||||||
|
defer logging.vmodule.Set("")
|
||||||
|
if !V(1) {
|
||||||
|
t.Error("V not enabled for 1")
|
||||||
|
}
|
||||||
|
if !V(2) {
|
||||||
|
t.Error("V not enabled for 2")
|
||||||
|
}
|
||||||
|
if V(3) {
|
||||||
|
t.Error("V enabled for 3")
|
||||||
|
}
|
||||||
|
V(2).Info("test")
|
||||||
|
if !contains(infoLog, "I", t) {
|
||||||
|
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
||||||
|
}
|
||||||
|
if !contains(infoLog, "test", t) {
|
||||||
|
t.Error("Info failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a vmodule of another file does not enable a log in this file.
|
||||||
|
func TestVmoduleOff(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
logging.vmodule.Set("notthisfile=2")
|
||||||
|
defer logging.vmodule.Set("")
|
||||||
|
for i := 1; i <= 3; i++ {
|
||||||
|
if V(Level(i)) {
|
||||||
|
t.Errorf("V enabled for %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
V(2).Info("test")
|
||||||
|
if contents(infoLog) != "" {
|
||||||
|
t.Error("V logged incorrectly")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vGlobs are patterns that match/don't match this file at V=2.
|
||||||
|
var vGlobs = map[string]bool{
|
||||||
|
// Easy to test the numeric match here.
|
||||||
|
"glog_test=1": false, // If -vmodule sets V to 1, V(2) will fail.
|
||||||
|
"glog_test=2": true,
|
||||||
|
"glog_test=3": true, // If -vmodule sets V to 1, V(3) will succeed.
|
||||||
|
// These all use 2 and check the patterns. All are true.
|
||||||
|
"*=2": true,
|
||||||
|
"?l*=2": true,
|
||||||
|
"????_*=2": true,
|
||||||
|
"??[mno]?_*t=2": true,
|
||||||
|
// These all use 2 and check the patterns. All are false.
|
||||||
|
"*x=2": false,
|
||||||
|
"m*=2": false,
|
||||||
|
"??_*=2": false,
|
||||||
|
"?[abc]?_*t=2": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that vmodule globbing works as advertised.
|
||||||
|
func testVmoduleGlob(pat string, match bool, t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
defer logging.vmodule.Set("")
|
||||||
|
logging.vmodule.Set(pat)
|
||||||
|
if V(2) != Verbose(match) {
|
||||||
|
t.Errorf("incorrect match for %q: got %t expected %t", pat, V(2), match)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a vmodule globbing works as advertised.
|
||||||
|
func TestVmoduleGlob(t *testing.T) {
|
||||||
|
for glob, match := range vGlobs {
|
||||||
|
testVmoduleGlob(glob, match, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRollover(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
var err error
|
||||||
|
defer func(previous func(error)) { logExitFunc = previous }(logExitFunc)
|
||||||
|
logExitFunc = func(e error) {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
defer func(previous uint64) { MaxSize = previous }(MaxSize)
|
||||||
|
MaxSize = 512
|
||||||
|
|
||||||
|
Info("x") // Be sure we have a file.
|
||||||
|
info, ok := logging.file[infoLog].(*syncBuffer)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("info wasn't created")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("info has initial error: %v", err)
|
||||||
|
}
|
||||||
|
fname0 := info.file.Name()
|
||||||
|
Info(strings.Repeat("x", int(MaxSize))) // force a rollover
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("info has error after big write: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the next log file gets a file name with a different
|
||||||
|
// time stamp.
|
||||||
|
//
|
||||||
|
// TODO: determine whether we need to support subsecond log
|
||||||
|
// rotation. C++ does not appear to handle this case (nor does it
|
||||||
|
// handle Daylight Savings Time properly).
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
Info("x") // create a new file
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error after rotation: %v", err)
|
||||||
|
}
|
||||||
|
fname1 := info.file.Name()
|
||||||
|
if fname0 == fname1 {
|
||||||
|
t.Errorf("info.f.Name did not change: %v", fname0)
|
||||||
|
}
|
||||||
|
if info.nbytes >= MaxSize {
|
||||||
|
t.Errorf("file size was not reset: %d", info.nbytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogBacktraceAt(t *testing.T) {
|
||||||
|
setFlags()
|
||||||
|
defer logging.swap(logging.newBuffers())
|
||||||
|
// The peculiar style of this code simplifies line counting and maintenance of the
|
||||||
|
// tracing block below.
|
||||||
|
var infoLine string
|
||||||
|
setTraceLocation := func(file string, line int, ok bool, delta int) {
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("could not get file:line")
|
||||||
|
}
|
||||||
|
_, file = filepath.Split(file)
|
||||||
|
infoLine = fmt.Sprintf("%s:%d", file, line+delta)
|
||||||
|
err := logging.traceLocation.Set(infoLine)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error setting log_backtrace_at: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Start of tracing block. These lines know about each other's relative position.
|
||||||
|
_, file, line, ok := runtime.Caller(0)
|
||||||
|
setTraceLocation(file, line, ok, +2) // Two lines between Caller and Info calls.
|
||||||
|
Info("we want a stack trace here")
|
||||||
|
}
|
||||||
|
numAppearances := strings.Count(contents(infoLog), infoLine)
|
||||||
|
if numAppearances < 2 {
|
||||||
|
// Need 2 appearances, one in the log header and one in the trace:
|
||||||
|
// log_test.go:281: I0511 16:36:06.952398 02238 log_test.go:280] we want a stack trace here
|
||||||
|
// ...
|
||||||
|
// github.com/glog/glog_test.go:280 (0x41ba91)
|
||||||
|
// ...
|
||||||
|
// We could be more precise but that would require knowing the details
|
||||||
|
// of the traceback format, which may not be dependable.
|
||||||
|
t.Fatal("got no trace back; log is ", contents(infoLog))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHeader(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
buf, _, _ := logging.header(infoLog, 0)
|
||||||
|
logging.putBuffer(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
10
logger/verbosity.go
Normal file
10
logger/verbosity.go
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
package logger
|
||||||
|
|
||||||
|
const (
|
||||||
|
Error = iota + 1
|
||||||
|
Warn
|
||||||
|
Info
|
||||||
|
Core
|
||||||
|
Debug
|
||||||
|
Detail
|
||||||
|
)
|
||||||
|
|
@ -5,6 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -75,7 +77,7 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuMiner) mine(block *types.Block) {
|
func (self *CpuMiner) mine(block *types.Block) {
|
||||||
minerlogger.Debugf("(re)started agent[%d]. mining...\n", self.index)
|
glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index)
|
||||||
|
|
||||||
// Reset the channel
|
// Reset the channel
|
||||||
self.chMu.Lock()
|
self.chMu.Lock()
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,13 @@ import (
|
||||||
"github.com/ethereum/ethash"
|
"github.com/ethereum/ethash"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
var minerlogger = logger.NewLogger("MINER")
|
|
||||||
|
|
||||||
type Miner struct {
|
type Miner struct {
|
||||||
worker *worker
|
worker *worker
|
||||||
|
|
||||||
MinAcceptedGasPrice *big.Int
|
MinAcceptedGasPrice *big.Int
|
||||||
Extra string
|
|
||||||
|
|
||||||
mining bool
|
mining bool
|
||||||
eth core.Backend
|
eth core.Backend
|
||||||
|
|
@ -61,3 +57,7 @@ func (self *Miner) Stop() {
|
||||||
func (self *Miner) HashRate() int64 {
|
func (self *Miner) HashRate() int64 {
|
||||||
return self.worker.HashRate()
|
return self.worker.HashRate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Miner) SetExtra(extra []byte) {
|
||||||
|
self.worker.extra = extra
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"gopkg.in/fatih/set.v0"
|
"gopkg.in/fatih/set.v0"
|
||||||
)
|
)
|
||||||
|
|
@ -71,7 +72,9 @@ type worker struct {
|
||||||
eth core.Backend
|
eth core.Backend
|
||||||
chain *core.ChainManager
|
chain *core.ChainManager
|
||||||
proc *core.BlockProcessor
|
proc *core.BlockProcessor
|
||||||
|
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
|
extra []byte
|
||||||
|
|
||||||
current *environment
|
current *environment
|
||||||
|
|
||||||
|
|
@ -144,7 +147,9 @@ out:
|
||||||
}
|
}
|
||||||
break out
|
break out
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
minerlogger.Infoln("Hash rate:", self.HashRate(), "Khash")
|
if glog.V(logger.Debug) {
|
||||||
|
glog.Infoln("Hash rate:", self.HashRate(), "Khash")
|
||||||
|
}
|
||||||
|
|
||||||
// XXX In case all mined a possible uncle
|
// XXX In case all mined a possible uncle
|
||||||
if atomic.LoadInt64(&self.atWork) == 0 {
|
if atomic.LoadInt64(&self.atWork) == 0 {
|
||||||
|
|
@ -171,7 +176,7 @@ func (self *worker) wait() {
|
||||||
}
|
}
|
||||||
self.mux.Post(core.NewMinedBlockEvent{block})
|
self.mux.Post(core.NewMinedBlockEvent{block})
|
||||||
|
|
||||||
minerlogger.Infof("🔨 Mined block #%v", block.Number())
|
glog.V(logger.Info).Infof("🔨 Mined block #%v", block.Number())
|
||||||
|
|
||||||
jsonlogger.LogJson(&logger.EthMinerNewBlock{
|
jsonlogger.LogJson(&logger.EthMinerNewBlock{
|
||||||
BlockHash: block.Hash().Hex(),
|
BlockHash: block.Hash().Hex(),
|
||||||
|
|
@ -207,6 +212,10 @@ func (self *worker) commitNewWork() {
|
||||||
defer self.uncleMu.Unlock()
|
defer self.uncleMu.Unlock()
|
||||||
|
|
||||||
block := self.chain.NewBlock(self.coinbase)
|
block := self.chain.NewBlock(self.coinbase)
|
||||||
|
if block.Time() == self.chain.CurrentBlock().Time() {
|
||||||
|
block.Header().Time++
|
||||||
|
}
|
||||||
|
block.Header().Extra = self.extra
|
||||||
|
|
||||||
self.current = env(block, self.eth)
|
self.current = env(block, self.eth)
|
||||||
for _, ancestor := range self.chain.GetAncestors(block, 7) {
|
for _, ancestor := range self.chain.GetAncestors(block, 7) {
|
||||||
|
|
@ -235,10 +244,13 @@ gasLimit:
|
||||||
from, _ := tx.From()
|
from, _ := tx.From()
|
||||||
self.chain.TxState().RemoveNonce(from, tx.Nonce())
|
self.chain.TxState().RemoveNonce(from, tx.Nonce())
|
||||||
remove = append(remove, tx)
|
remove = append(remove, tx)
|
||||||
minerlogger.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
|
|
||||||
minerlogger.Infoln(tx)
|
if glog.V(logger.Info) {
|
||||||
|
glog.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
|
||||||
|
}
|
||||||
|
glog.V(logger.Debug).Infoln(tx)
|
||||||
case state.IsGasLimitErr(err):
|
case state.IsGasLimitErr(err):
|
||||||
minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i)
|
glog.V(logger.Info).Infof("Gas limit reached for block. %d TXs included in this block\n", i)
|
||||||
// Break on gas limit
|
// Break on gas limit
|
||||||
break gasLimit
|
break gasLimit
|
||||||
default:
|
default:
|
||||||
|
|
@ -257,15 +269,15 @@ gasLimit:
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := self.commitUncle(uncle.Header()); err != nil {
|
if err := self.commitUncle(uncle.Header()); err != nil {
|
||||||
minerlogger.Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
|
glog.V(logger.Info).Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
|
||||||
minerlogger.Debugln(uncle)
|
glog.V(logger.Debug).Infoln(uncle)
|
||||||
badUncles = append(badUncles, hash)
|
badUncles = append(badUncles, hash)
|
||||||
} else {
|
} else {
|
||||||
minerlogger.Infof("commiting %x as uncle\n", hash[:4])
|
glog.V(logger.Info).Infof("commiting %x as uncle\n", hash[:4])
|
||||||
uncles = append(uncles, uncle.Header())
|
uncles = append(uncles, uncle.Header())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
minerlogger.Infof("commit new work on block %v with %d txs & %d uncles\n", self.current.block.Number(), tcount, len(uncles))
|
glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles\n", self.current.block.Number(), tcount, len(uncles))
|
||||||
for _, hash := range badUncles {
|
for _, hash := range badUncles {
|
||||||
delete(self.possibleUncles, hash)
|
delete(self.possibleUncles, hash)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,8 @@ func (err *decodeError) Error() string {
|
||||||
|
|
||||||
func wrapStreamError(err error, typ reflect.Type) error {
|
func wrapStreamError(err error, typ reflect.Type) error {
|
||||||
switch err {
|
switch err {
|
||||||
|
case ErrCanonInt:
|
||||||
|
return &decodeError{msg: "canon int error appends zero's", typ: typ}
|
||||||
case ErrExpectedList:
|
case ErrExpectedList:
|
||||||
return &decodeError{msg: "expected input list", typ: typ}
|
return &decodeError{msg: "expected input list", typ: typ}
|
||||||
case ErrExpectedString:
|
case ErrExpectedString:
|
||||||
|
|
@ -184,6 +186,12 @@ func decodeBigInt(s *Stream, val reflect.Value) error {
|
||||||
i = new(big.Int)
|
i = new(big.Int)
|
||||||
val.Set(reflect.ValueOf(i))
|
val.Set(reflect.ValueOf(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reject big integers which are zero appended
|
||||||
|
if len(b) > 0 && b[0] == 0 {
|
||||||
|
return wrapStreamError(ErrCanonInt, val.Type())
|
||||||
|
}
|
||||||
|
|
||||||
i.SetBytes(b)
|
i.SetBytes(b)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -460,6 +468,7 @@ var (
|
||||||
// Other errors
|
// Other errors
|
||||||
ErrExpectedString = errors.New("rlp: expected String or Byte")
|
ErrExpectedString = errors.New("rlp: expected String or Byte")
|
||||||
ErrExpectedList = errors.New("rlp: expected List")
|
ErrExpectedList = errors.New("rlp: expected List")
|
||||||
|
ErrCanonInt = errors.New("rlp: expected Int")
|
||||||
ErrElemTooLarge = errors.New("rlp: element is larger than containing list")
|
ErrElemTooLarge = errors.New("rlp: element is larger than containing list")
|
||||||
|
|
||||||
// internal errors
|
// internal errors
|
||||||
|
|
|
||||||
|
|
@ -312,6 +312,7 @@ var decodeTests = []decodeTest{
|
||||||
// big ints
|
// big ints
|
||||||
{input: "01", ptr: new(*big.Int), value: big.NewInt(1)},
|
{input: "01", ptr: new(*big.Int), value: big.NewInt(1)},
|
||||||
{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt},
|
{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt},
|
||||||
|
{input: "820001", ptr: new(big.Int), error: "rlp: canon int error appends zero's for *big.Int"},
|
||||||
{input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works
|
{input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works
|
||||||
{input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"},
|
{input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ func mustConvertHeader(in btHeader) *types.Header {
|
||||||
Coinbase: mustConvertAddress(in.Coinbase),
|
Coinbase: mustConvertAddress(in.Coinbase),
|
||||||
UncleHash: mustConvertHash(in.UncleHash),
|
UncleHash: mustConvertHash(in.UncleHash),
|
||||||
ParentHash: mustConvertHash(in.ParentHash),
|
ParentHash: mustConvertHash(in.ParentHash),
|
||||||
Extra: string(mustConvertBytes(in.ExtraData)),
|
Extra: mustConvertBytes(in.ExtraData),
|
||||||
GasUsed: mustConvertBigInt10(in.GasUsed),
|
GasUsed: mustConvertBigInt10(in.GasUsed),
|
||||||
GasLimit: mustConvertBigInt10(in.GasLimit),
|
GasLimit: mustConvertBigInt10(in.GasLimit),
|
||||||
Difficulty: mustConvertBigInt10(in.Difficulty),
|
Difficulty: mustConvertBigInt10(in.Difficulty),
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -9,8 +9,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/tests/helper"
|
"github.com/ethereum/go-ethereum/tests/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -80,14 +82,13 @@ func RunVmTest(p string, t *testing.T) {
|
||||||
tests := make(map[string]VmTest)
|
tests := make(map[string]VmTest)
|
||||||
helper.CreateFileTests(t, p, &tests)
|
helper.CreateFileTests(t, p, &tests)
|
||||||
|
|
||||||
for name, test := range tests {
|
|
||||||
/*
|
|
||||||
vm.Debug = true
|
vm.Debug = true
|
||||||
helper.Logger.SetLogLevel(5)
|
glog.SetV(4)
|
||||||
if name != "Call1MB1024Calldepth" {
|
glog.SetToStderr(true)
|
||||||
|
for name, test := range tests {
|
||||||
|
if name != "stackLimitPush32_1024" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
statedb := state.New(common.Hash{}, db)
|
statedb := state.New(common.Hash{}, db)
|
||||||
for addr, account := range test.Pre {
|
for addr, account := range test.Pre {
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
|
||||||
for _, envelope := range envelopes {
|
for _, envelope := range envelopes {
|
||||||
if err := self.add(envelope); err != nil {
|
if err := self.add(envelope); err != nil {
|
||||||
// TODO Punish peer here. Invalid envelope.
|
// TODO Punish peer here. Invalid envelope.
|
||||||
peer.Infoln(err)
|
peer.Debugln(err)
|
||||||
}
|
}
|
||||||
wpeer.addKnown(envelope)
|
wpeer.addKnown(envelope)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue