mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
merge cleanup
good bye old friends.
This commit is contained in:
parent
f536890746
commit
125ab77050
177 changed files with 13 additions and 37579 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "cmd/mist/assets/ext/expanse.js"]
|
||||
path = cmd/mist/assets/ext/expanse.js
|
||||
url = https://github.com/expanse-org/web3.js
|
||||
329
Godeps/Godeps.json
generated
329
Godeps/Godeps.json
generated
|
|
@ -1,329 +0,0 @@
|
|||
{
|
||||
"ImportPath": "github.com/expanse-org/go-expanse",
|
||||
"GoVersion": "go1.5.2",
|
||||
"GodepVersion": "v74",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/Gustav-Simonsson/go-opencl/cl",
|
||||
"Rev": "593e01cfc4f3353585015321e01951d4a907d3ef"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cespare/cp",
|
||||
"Rev": "165db2f241fd235aec29ba6d9b1ccd5f1c14637c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/davecgh/go-spew/spew",
|
||||
"Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/expanse-org/ethash",
|
||||
"Comment": "v23.1-247-g2e80de5",
|
||||
"Rev": "2e80de5022370cfe632195b1720db52d07ff8a77"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/fatih/color",
|
||||
"Comment": "v0.1-12-g9aae6aa",
|
||||
"Rev": "9aae6aaa22315390f03959adca2c4d395b02fcef"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gizak/termui",
|
||||
"Rev": "08a5d3f67b7d9ec87830ea39c48e570a1f18531f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/snappy",
|
||||
"Rev": "799c780093d646c1b79d30894e22512c319fa137"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/golang-lru",
|
||||
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/golang-lru/simplelru",
|
||||
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/huin/goupnp",
|
||||
"Rev": "46bde78b11f3f021f2a511df138be9e2fc7506e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/huin/goupnp/dcps/internetgateway1",
|
||||
"Rev": "46bde78b11f3f021f2a511df138be9e2fc7506e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/huin/goupnp/dcps/internetgateway2",
|
||||
"Rev": "46bde78b11f3f021f2a511df138be9e2fc7506e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/huin/goupnp/httpu",
|
||||
"Rev": "46bde78b11f3f021f2a511df138be9e2fc7506e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/huin/goupnp/scpd",
|
||||
"Rev": "46bde78b11f3f021f2a511df138be9e2fc7506e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/huin/goupnp/soap",
|
||||
"Rev": "46bde78b11f3f021f2a511df138be9e2fc7506e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/huin/goupnp/ssdp",
|
||||
"Rev": "46bde78b11f3f021f2a511df138be9e2fc7506e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jackpal/gateway",
|
||||
"Rev": "192609c58b8985e645cbe82ddcb28a4362ca0fdc"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jackpal/go-nat-pmp",
|
||||
"Rev": "46523a463303c6ede3ddfe45bde1c7ed52ebaacd"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-colorable",
|
||||
"Rev": "9fdad7c47650b7d2e1da50644c1f4ba7f172f252"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-isatty",
|
||||
"Rev": "56b76bdf51f7708750eac80fa38b952bb9f32639"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-runewidth",
|
||||
"Comment": "travisish-44-ge882a96",
|
||||
"Rev": "e882a96ec18dd43fa283187b66af74497c9101c0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/microsoft/go-winio",
|
||||
"Comment": "v0.2.0",
|
||||
"Rev": "9e2895e5f6c3f16473b91d37fae6e89990a4520c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/nsf/termbox-go",
|
||||
"Rev": "362329b0aa6447eadd52edd8d660ec1dff470295"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pborman/uuid",
|
||||
"Comment": "v1.0-6-g0f1a469",
|
||||
"Rev": "0f1a46960a86dcdf5dd30d3e6568a497a997909f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/peterh/liner",
|
||||
"Rev": "ad1edfd30321d8f006ccf05f1e0524adeb943060"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rcrowley/go-metrics",
|
||||
"Rev": "51425a2415d21afadfd55cd93432c0bc69e9598d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rjeczalik/notify",
|
||||
"Rev": "f627deca7a510d96f0ef9388f2d0e8b16d21f87f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto",
|
||||
"Rev": "53221230c215611a90762720c9042ac782ef74ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/ast",
|
||||
"Rev": "53221230c215611a90762720c9042ac782ef74ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/dbg",
|
||||
"Rev": "53221230c215611a90762720c9042ac782ef74ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/file",
|
||||
"Rev": "53221230c215611a90762720c9042ac782ef74ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/parser",
|
||||
"Rev": "53221230c215611a90762720c9042ac782ef74ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/registry",
|
||||
"Rev": "53221230c215611a90762720c9042ac782ef74ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/token",
|
||||
"Rev": "53221230c215611a90762720c9042ac782ef74ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rs/cors",
|
||||
"Rev": "5950cf11d77f8a61b432a25dd4d444b4ced01379"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rs/xhandler",
|
||||
"Rev": "d9d9599b6aaf6a058cb7b1f48291ded2cbd13390"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/cache",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/comparer",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/errors",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/filter",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/iterator",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/journal",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/memdb",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/opt",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/storage",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/table",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb/util",
|
||||
"Rev": "917f41c560270110ceb73c5b38be2a9127387071"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/pbkdf2",
|
||||
"Rev": "1f22c0103821b9390939b6776727195525381532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ripemd160",
|
||||
"Rev": "1f22c0103821b9390939b6776727195525381532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/scrypt",
|
||||
"Rev": "1f22c0103821b9390939b6776727195525381532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/context",
|
||||
"Rev": "8968c61983e8f51a91b8c0ef25bf739278c89634"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html",
|
||||
"Rev": "8968c61983e8f51a91b8c0ef25bf739278c89634"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html/atom",
|
||||
"Rev": "8968c61983e8f51a91b8c0ef25bf739278c89634"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html/charset",
|
||||
"Rev": "8968c61983e8f51a91b8c0ef25bf739278c89634"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/websocket",
|
||||
"Rev": "8968c61983e8f51a91b8c0ef25bf739278c89634"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
"Rev": "50c6bc5e4292a1d4e65c6e9be5f53be28bcbe28e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/charmap",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/htmlindex",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/internal",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/internal/identifier",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/japanese",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/korean",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/simplifiedchinese",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/traditionalchinese",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/unicode",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/internal/tag",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/internal/utf8internal",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/language",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/runes",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/transform",
|
||||
"Rev": "09761194ac5034a97b2bfad4f5b896b0ac350b3e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/tools/go/ast/astutil",
|
||||
"Rev": "758728c4b28cfbac299730969ef8f655c4761283"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/tools/imports",
|
||||
"Rev": "758728c4b28cfbac299730969ef8f655c4761283"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/check.v1",
|
||||
"Rev": "4f90aeace3a26ad7021961c297b22c42160c7b25"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/fatih/set.v0",
|
||||
"Comment": "v0.1.0-3-g27c4092",
|
||||
"Rev": "27c40922c40b43fe04554d8223a402af3ea333f3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/karalabe/cookiejar.v2/collections/prque",
|
||||
"Rev": "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/urfave/cli.v1",
|
||||
"Comment": "v1.17.0",
|
||||
"Rev": "01857ac33766ce0c93856370626f9799281c14f4"
|
||||
}
|
||||
]
|
||||
}
|
||||
628
Godeps/_workspace/src/github.com/ethereum/ethash/ethash_opencl.go
generated
vendored
628
Godeps/_workspace/src/github.com/ethereum/ethash/ethash_opencl.go
generated
vendored
|
|
@ -1,628 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build opencl
|
||||
|
||||
package ethash
|
||||
|
||||
//#cgo LDFLAGS: -w
|
||||
//#include <stdint.h>
|
||||
//#include <string.h>
|
||||
//#include "src/libethash/internal.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
mrand "math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Gustav-Simonsson/go-opencl/cl"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/pow"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
This code have two main entry points:
|
||||
|
||||
1. The initCL(...) function configures one or more OpenCL device
|
||||
(for now only GPU) and loads the Ethash DAG onto device memory
|
||||
|
||||
2. The Search(...) function loads a Ethash nonce into device(s) memory and
|
||||
executes the Ethash OpenCL kernel.
|
||||
|
||||
Throughout the code, we refer to "host memory" and "device memory".
|
||||
For most systems (e.g. regular PC GPU miner) the host memory is RAM and
|
||||
device memory is the GPU global memory (e.g. GDDR5).
|
||||
|
||||
References mentioned in code comments:
|
||||
|
||||
1. https://github.com/ethereum/wiki/wiki/Ethash
|
||||
2. https://github.com/ethereum/cpp-ethereum/blob/develop/libethash-cl/ethash_cl_miner.cpp
|
||||
3. https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/
|
||||
4. http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_OpenCL_Programming_User_Guide.pdf
|
||||
|
||||
*/
|
||||
|
||||
type OpenCLDevice struct {
|
||||
deviceId int
|
||||
device *cl.Device
|
||||
openCL11 bool // OpenCL version 1.1 and 1.2 are handled a bit different
|
||||
openCL12 bool
|
||||
|
||||
dagBuf *cl.MemObject // Ethash full DAG in device mem
|
||||
headerBuf *cl.MemObject // Hash of block-to-mine in device mem
|
||||
searchBuffers []*cl.MemObject
|
||||
|
||||
searchKernel *cl.Kernel
|
||||
hashKernel *cl.Kernel
|
||||
|
||||
queue *cl.CommandQueue
|
||||
ctx *cl.Context
|
||||
workGroupSize int
|
||||
|
||||
nonceRand *mrand.Rand // seeded by crypto/rand, see comments where it's initialised
|
||||
result common.Hash
|
||||
}
|
||||
|
||||
type OpenCLMiner struct {
|
||||
mu sync.Mutex
|
||||
|
||||
ethash *Ethash // Ethash full DAG & cache in host mem
|
||||
|
||||
deviceIds []int
|
||||
devices []*OpenCLDevice
|
||||
|
||||
dagSize uint64
|
||||
|
||||
hashRate int32 // Go atomics & uint64 have some issues; int32 is supported on all platforms
|
||||
}
|
||||
|
||||
type pendingSearch struct {
|
||||
bufIndex uint32
|
||||
startNonce uint64
|
||||
}
|
||||
|
||||
const (
|
||||
SIZEOF_UINT32 = 4
|
||||
|
||||
// See [1]
|
||||
ethashMixBytesLen = 128
|
||||
ethashAccesses = 64
|
||||
|
||||
// See [4]
|
||||
workGroupSize = 32 // must be multiple of 8
|
||||
maxSearchResults = 63
|
||||
searchBufSize = 2
|
||||
globalWorkSize = 1024 * 256
|
||||
)
|
||||
|
||||
func NewCL(deviceIds []int) *OpenCLMiner {
|
||||
ids := make([]int, len(deviceIds))
|
||||
copy(ids, deviceIds)
|
||||
return &OpenCLMiner{
|
||||
ethash: New(),
|
||||
dagSize: 0, // to see if we need to update DAG.
|
||||
deviceIds: ids,
|
||||
}
|
||||
}
|
||||
|
||||
func PrintDevices() {
|
||||
fmt.Println("=============================================")
|
||||
fmt.Println("============ OpenCL Device Info =============")
|
||||
fmt.Println("=============================================")
|
||||
|
||||
var found []*cl.Device
|
||||
|
||||
platforms, err := cl.GetPlatforms()
|
||||
if err != nil {
|
||||
fmt.Println("Plaform error (check your OpenCL installation):", err)
|
||||
return
|
||||
}
|
||||
|
||||
for i, p := range platforms {
|
||||
fmt.Println("Platform id ", i)
|
||||
fmt.Println("Platform Name ", p.Name())
|
||||
fmt.Println("Platform Vendor ", p.Vendor())
|
||||
fmt.Println("Platform Version ", p.Version())
|
||||
fmt.Println("Platform Extensions ", p.Extensions())
|
||||
fmt.Println("Platform Profile ", p.Profile())
|
||||
fmt.Println("")
|
||||
|
||||
devices, err := cl.GetDevices(p, cl.DeviceTypeGPU)
|
||||
if err != nil {
|
||||
fmt.Println("Device error (check your GPU drivers) :", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, d := range devices {
|
||||
fmt.Println("Device OpenCL id ", i)
|
||||
fmt.Println("Device id for mining ", len(found))
|
||||
fmt.Println("Device Name ", d.Name())
|
||||
fmt.Println("Vendor ", d.Vendor())
|
||||
fmt.Println("Version ", d.Version())
|
||||
fmt.Println("Driver version ", d.DriverVersion())
|
||||
fmt.Println("Address bits ", d.AddressBits())
|
||||
fmt.Println("Max clock freq ", d.MaxClockFrequency())
|
||||
fmt.Println("Global mem size ", d.GlobalMemSize())
|
||||
fmt.Println("Max constant buffer size", d.MaxConstantBufferSize())
|
||||
fmt.Println("Max mem alloc size ", d.MaxMemAllocSize())
|
||||
fmt.Println("Max compute units ", d.MaxComputeUnits())
|
||||
fmt.Println("Max work group size ", d.MaxWorkGroupSize())
|
||||
fmt.Println("Max work item sizes ", d.MaxWorkItemSizes())
|
||||
fmt.Println("=============================================")
|
||||
|
||||
found = append(found, d)
|
||||
}
|
||||
}
|
||||
if len(found) == 0 {
|
||||
fmt.Println("Found no GPU(s). Check that your OS can see the GPU(s)")
|
||||
} else {
|
||||
var idsFormat string
|
||||
for i := 0; i < len(found); i++ {
|
||||
idsFormat += strconv.Itoa(i)
|
||||
if i != len(found)-1 {
|
||||
idsFormat += ","
|
||||
}
|
||||
}
|
||||
fmt.Printf("Found %v devices. Benchmark first GPU: gexp gpubench 0\n", len(found))
|
||||
fmt.Printf("Mine using all GPUs: gexp --minegpu %v\n", idsFormat)
|
||||
}
|
||||
}
|
||||
|
||||
// See [2]. We basically do the same here, but the Go OpenCL bindings
|
||||
// are at a slightly higher abtraction level.
|
||||
func InitCL(blockNum uint64, c *OpenCLMiner) error {
|
||||
platforms, err := cl.GetPlatforms()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Plaform error: %v\nCheck your OpenCL installation and then run gexp gpuinfo", err)
|
||||
}
|
||||
|
||||
var devices []*cl.Device
|
||||
for _, p := range platforms {
|
||||
ds, err := cl.GetDevices(p, cl.DeviceTypeGPU)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Devices error: %v\nCheck your GPU drivers and then run gexp gpuinfo", err)
|
||||
}
|
||||
for _, d := range ds {
|
||||
devices = append(devices, d)
|
||||
}
|
||||
}
|
||||
|
||||
pow := New()
|
||||
_ = pow.getDAG(blockNum) // generates DAG if we don't have it
|
||||
pow.Light.getCache(blockNum) // and cache
|
||||
|
||||
c.ethash = pow
|
||||
dagSize := uint64(C.ethash_get_datasize(C.uint64_t(blockNum)))
|
||||
c.dagSize = dagSize
|
||||
|
||||
for _, id := range c.deviceIds {
|
||||
if id > len(devices)-1 {
|
||||
return fmt.Errorf("Device id not found. See available device ids with: gexp gpuinfo")
|
||||
} else {
|
||||
err := initCLDevice(id, devices[id], c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(c.devices) == 0 {
|
||||
return fmt.Errorf("No GPU devices found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initCLDevice(deviceId int, device *cl.Device, c *OpenCLMiner) error {
|
||||
devMaxAlloc := uint64(device.MaxMemAllocSize())
|
||||
devGlobalMem := uint64(device.GlobalMemSize())
|
||||
|
||||
// TODO: more fine grained version logic
|
||||
if device.Version() == "OpenCL 1.0" {
|
||||
fmt.Println("Device OpenCL version not supported: ", device.Version())
|
||||
return fmt.Errorf("opencl version not supported")
|
||||
}
|
||||
|
||||
var cl11, cl12 bool
|
||||
if device.Version() == "OpenCL 1.1" {
|
||||
cl11 = true
|
||||
}
|
||||
if device.Version() == "OpenCL 1.2" {
|
||||
cl12 = true
|
||||
}
|
||||
|
||||
// log warnings but carry on; some device drivers report inaccurate values
|
||||
if c.dagSize > devGlobalMem {
|
||||
fmt.Printf("WARNING: device memory may be insufficient: %v. DAG size: %v.\n", devGlobalMem, c.dagSize)
|
||||
}
|
||||
|
||||
if c.dagSize > devMaxAlloc {
|
||||
fmt.Printf("WARNING: DAG size (%v) larger than device max memory allocation size (%v).\n", c.dagSize, devMaxAlloc)
|
||||
fmt.Printf("You probably have to export GPU_MAX_ALLOC_PERCENT=95\n")
|
||||
}
|
||||
|
||||
fmt.Printf("Initialising device %v: %v\n", deviceId, device.Name())
|
||||
|
||||
context, err := cl.CreateContext([]*cl.Device{device})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed creating context: %v", err)
|
||||
}
|
||||
|
||||
// TODO: test running with CL_QUEUE_PROFILING_ENABLE for profiling?
|
||||
queue, err := context.CreateCommandQueue(device, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("command queue err: %v", err)
|
||||
}
|
||||
|
||||
// See [4] section 3.2 and [3] "clBuildProgram".
|
||||
// The OpenCL kernel code is compiled at run-time.
|
||||
kvs := make(map[string]string, 4)
|
||||
kvs["GROUP_SIZE"] = strconv.FormatUint(workGroupSize, 10)
|
||||
kvs["DAG_SIZE"] = strconv.FormatUint(c.dagSize/ethashMixBytesLen, 10)
|
||||
kvs["ACCESSES"] = strconv.FormatUint(ethashAccesses, 10)
|
||||
kvs["MAX_OUTPUTS"] = strconv.FormatUint(maxSearchResults, 10)
|
||||
kernelCode := replaceWords(kernel, kvs)
|
||||
|
||||
program, err := context.CreateProgramWithSource([]string{kernelCode})
|
||||
if err != nil {
|
||||
return fmt.Errorf("program err: %v", err)
|
||||
}
|
||||
|
||||
/* if using AMD OpenCL impl, you can set this to debug on x86 CPU device.
|
||||
see AMD OpenCL programming guide section 4.2
|
||||
|
||||
export in shell before running:
|
||||
export AMD_OCL_BUILD_OPTIONS_APPEND="-g -O0"
|
||||
export CPU_MAX_COMPUTE_UNITS=1
|
||||
|
||||
buildOpts := "-g -cl-opt-disable"
|
||||
|
||||
*/
|
||||
buildOpts := ""
|
||||
err = program.BuildProgram([]*cl.Device{device}, buildOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("program build err: %v", err)
|
||||
}
|
||||
|
||||
var searchKernelName, hashKernelName string
|
||||
searchKernelName = "ethash_search"
|
||||
hashKernelName = "ethash_hash"
|
||||
|
||||
searchKernel, err := program.CreateKernel(searchKernelName)
|
||||
hashKernel, err := program.CreateKernel(hashKernelName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("kernel err: %v", err)
|
||||
}
|
||||
|
||||
// TODO: when this DAG size appears, patch the Go bindings
|
||||
// (context.go) to work with uint64 as size_t
|
||||
if c.dagSize > math.MaxInt32 {
|
||||
fmt.Println("DAG too large for allocation.")
|
||||
return fmt.Errorf("DAG too large for alloc")
|
||||
}
|
||||
|
||||
// TODO: patch up Go bindings to work with size_t, will overflow if > maxint32
|
||||
// TODO: fuck. shit's gonna overflow around 2017-06-09 12:17:02
|
||||
dagBuf := *(new(*cl.MemObject))
|
||||
dagBuf, err = context.CreateEmptyBuffer(cl.MemReadOnly, int(c.dagSize))
|
||||
if err != nil {
|
||||
return fmt.Errorf("allocating dag buf failed: %v", err)
|
||||
}
|
||||
|
||||
// write DAG to device mem
|
||||
dagPtr := unsafe.Pointer(c.ethash.Full.current.ptr.data)
|
||||
_, err = queue.EnqueueWriteBuffer(dagBuf, true, 0, int(c.dagSize), dagPtr, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing to dag buf failed: %v", err)
|
||||
}
|
||||
|
||||
searchBuffers := make([]*cl.MemObject, searchBufSize)
|
||||
for i := 0; i < searchBufSize; i++ {
|
||||
searchBuff, err := context.CreateEmptyBuffer(cl.MemWriteOnly, (1+maxSearchResults)*SIZEOF_UINT32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("search buffer err: %v", err)
|
||||
}
|
||||
searchBuffers[i] = searchBuff
|
||||
}
|
||||
|
||||
headerBuf, err := context.CreateEmptyBuffer(cl.MemReadOnly, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("header buffer err: %v", err)
|
||||
}
|
||||
|
||||
// Unique, random nonces are crucial for mining efficieny.
|
||||
// While we do not need cryptographically secure PRNG for nonces,
|
||||
// we want to have uniform distribution and minimal repetition of nonces.
|
||||
// We could guarantee strict uniqueness of nonces by generating unique ranges,
|
||||
// but a int64 seed from crypto/rand should be good enough.
|
||||
// we then use math/rand for speed and to avoid draining OS entropy pool
|
||||
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nonceRand := mrand.New(mrand.NewSource(seed.Int64()))
|
||||
|
||||
deviceStruct := &OpenCLDevice{
|
||||
deviceId: deviceId,
|
||||
device: device,
|
||||
openCL11: cl11,
|
||||
openCL12: cl12,
|
||||
|
||||
dagBuf: dagBuf,
|
||||
headerBuf: headerBuf,
|
||||
searchBuffers: searchBuffers,
|
||||
|
||||
searchKernel: searchKernel,
|
||||
hashKernel: hashKernel,
|
||||
|
||||
queue: queue,
|
||||
ctx: context,
|
||||
|
||||
workGroupSize: workGroupSize,
|
||||
|
||||
nonceRand: nonceRand,
|
||||
}
|
||||
c.devices = append(c.devices, deviceStruct)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OpenCLMiner) Search(block pow.Block, stop <-chan struct{}, index int) (uint64, []byte) {
|
||||
c.mu.Lock()
|
||||
newDagSize := uint64(C.ethash_get_datasize(C.uint64_t(block.NumberU64())))
|
||||
if newDagSize > c.dagSize {
|
||||
// TODO: clean up buffers from previous DAG?
|
||||
err := InitCL(block.NumberU64(), c)
|
||||
if err != nil {
|
||||
fmt.Println("OpenCL init error: ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
}
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// Avoid unneeded OpenCL initialisation if we received stop while running InitCL
|
||||
select {
|
||||
case <-stop:
|
||||
return 0, []byte{0}
|
||||
default:
|
||||
}
|
||||
|
||||
headerHash := block.HashNoNonce()
|
||||
diff := block.Difficulty()
|
||||
target256 := new(big.Int).Div(maxUint256, diff)
|
||||
target64 := new(big.Int).Rsh(target256, 192).Uint64()
|
||||
var zero uint32 = 0
|
||||
|
||||
d := c.devices[index]
|
||||
|
||||
_, err := d.queue.EnqueueWriteBuffer(d.headerBuf, false, 0, 32, unsafe.Pointer(&headerHash[0]), nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clEnqueueWriterBuffer : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
for i := 0; i < searchBufSize; i++ {
|
||||
_, err := d.queue.EnqueueWriteBuffer(d.searchBuffers[i], false, 0, 4, unsafe.Pointer(&zero), nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clEnqueueWriterBuffer : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
}
|
||||
|
||||
// wait for all search buffers to complete
|
||||
err = d.queue.Finish()
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clFinish : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
err = d.searchKernel.SetArg(1, d.headerBuf)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clSetKernelArg : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
err = d.searchKernel.SetArg(2, d.dagBuf)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clSetKernelArg : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
err = d.searchKernel.SetArg(4, target64)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clSetKernelArg : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
err = d.searchKernel.SetArg(5, uint32(math.MaxUint32))
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clSetKernelArg : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
// wait on this before returning
|
||||
var preReturnEvent *cl.Event
|
||||
if d.openCL12 {
|
||||
preReturnEvent, err = d.ctx.CreateUserEvent()
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search create CL user event : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
}
|
||||
|
||||
pending := make([]pendingSearch, 0, searchBufSize)
|
||||
var p *pendingSearch
|
||||
searchBufIndex := uint32(0)
|
||||
var checkNonce uint64
|
||||
loops := int64(0)
|
||||
prevHashRate := int32(0)
|
||||
start := time.Now().UnixNano()
|
||||
// we grab a single random nonce and sets this as argument to the kernel search function
|
||||
// the device will then add each local threads gid to the nonce, creating a unique nonce
|
||||
// for each device computing unit executing in parallel
|
||||
initNonce := uint64(d.nonceRand.Int63())
|
||||
for nonce := initNonce; ; nonce += uint64(globalWorkSize) {
|
||||
select {
|
||||
case <-stop:
|
||||
|
||||
/*
|
||||
if d.openCL12 {
|
||||
err = cl.WaitForEvents([]*cl.Event{preReturnEvent})
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search WaitForEvents: ", err)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
atomic.AddInt32(&c.hashRate, -prevHashRate)
|
||||
return 0, []byte{0}
|
||||
default:
|
||||
}
|
||||
|
||||
if (loops % (1 << 7)) == 0 {
|
||||
elapsed := time.Now().UnixNano() - start
|
||||
// TODO: verify if this is correct hash rate calculation
|
||||
hashes := (float64(1e9) / float64(elapsed)) * float64(loops*1024*256)
|
||||
hashrateDiff := int32(hashes) - prevHashRate
|
||||
prevHashRate = int32(hashes)
|
||||
atomic.AddInt32(&c.hashRate, hashrateDiff)
|
||||
}
|
||||
loops++
|
||||
|
||||
err = d.searchKernel.SetArg(0, d.searchBuffers[searchBufIndex])
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clSetKernelArg : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
err = d.searchKernel.SetArg(3, nonce)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clSetKernelArg : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
// execute kernel
|
||||
_, err := d.queue.EnqueueNDRangeKernel(
|
||||
d.searchKernel,
|
||||
[]int{0},
|
||||
[]int{globalWorkSize},
|
||||
[]int{d.workGroupSize},
|
||||
nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clEnqueueNDRangeKernel : ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
pending = append(pending, pendingSearch{bufIndex: searchBufIndex, startNonce: nonce})
|
||||
searchBufIndex = (searchBufIndex + 1) % searchBufSize
|
||||
|
||||
if len(pending) == searchBufSize {
|
||||
p = &(pending[searchBufIndex])
|
||||
cres, _, err := d.queue.EnqueueMapBuffer(d.searchBuffers[p.bufIndex], true,
|
||||
cl.MapFlagRead, 0, (1+maxSearchResults)*SIZEOF_UINT32,
|
||||
nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clEnqueueMapBuffer: ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
results := cres.ByteSlice()
|
||||
nfound := binary.LittleEndian.Uint32(results)
|
||||
nfound = uint32(math.Min(float64(nfound), float64(maxSearchResults)))
|
||||
// OpenCL returns the offsets from the start nonce
|
||||
for i := uint32(0); i < nfound; i++ {
|
||||
lo := (i + 1) * SIZEOF_UINT32
|
||||
hi := (i + 2) * SIZEOF_UINT32
|
||||
upperNonce := uint64(binary.LittleEndian.Uint32(results[lo:hi]))
|
||||
checkNonce = p.startNonce + upperNonce
|
||||
if checkNonce != 0 {
|
||||
// We verify that the nonce is indeed a solution by
|
||||
// executing the Ethash verification function (on the CPU).
|
||||
cache := c.ethash.Light.getCache(block.NumberU64())
|
||||
ok, mixDigest, result := cache.compute(c.dagSize, headerHash, checkNonce)
|
||||
|
||||
// TODO: return result first
|
||||
if ok && result.Big().Cmp(target256) <= 0 {
|
||||
_, err = d.queue.EnqueueUnmapMemObject(d.searchBuffers[p.bufIndex], cres, nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clEnqueueUnmapMemObject: ", err)
|
||||
}
|
||||
if d.openCL12 {
|
||||
err = cl.WaitForEvents([]*cl.Event{preReturnEvent})
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search WaitForEvents: ", err)
|
||||
}
|
||||
}
|
||||
return checkNonce, mixDigest.Bytes()
|
||||
}
|
||||
_, err := d.queue.EnqueueWriteBuffer(d.searchBuffers[p.bufIndex], false, 0, 4, unsafe.Pointer(&zero), nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search cl: EnqueueWriteBuffer", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = d.queue.EnqueueUnmapMemObject(d.searchBuffers[p.bufIndex], cres, nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clEnqueueUnMapMemObject: ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
pending = append(pending[:searchBufIndex], pending[searchBufIndex+1:]...)
|
||||
}
|
||||
}
|
||||
if d.openCL12 {
|
||||
err := cl.WaitForEvents([]*cl.Event{preReturnEvent})
|
||||
if err != nil {
|
||||
fmt.Println("Error in Search clWaitForEvents: ", err)
|
||||
return 0, []byte{0}
|
||||
}
|
||||
}
|
||||
return 0, []byte{0}
|
||||
}
|
||||
|
||||
func (c *OpenCLMiner) Verify(block pow.Block) bool {
|
||||
return c.ethash.Light.Verify(block)
|
||||
}
|
||||
func (c *OpenCLMiner) GetHashrate() int64 {
|
||||
return int64(atomic.LoadInt32(&c.hashRate))
|
||||
}
|
||||
func (c *OpenCLMiner) Turbo(on bool) {
|
||||
// This is GPU mining. Always be turbo.
|
||||
}
|
||||
|
||||
func replaceWords(text string, kvs map[string]string) string {
|
||||
for k, v := range kvs {
|
||||
text = strings.Replace(text, k, v, -1)
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func logErr(err error) {
|
||||
if err != nil {
|
||||
fmt.Println("Error in OpenCL call:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func argErr(err error) error {
|
||||
return fmt.Errorf("arg err: %v", err)
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/expanse-org/ethash/.gitignore
generated
vendored
12
Godeps/_workspace/src/github.com/expanse-org/ethash/.gitignore
generated
vendored
|
|
@ -1,12 +0,0 @@
|
|||
.idea/
|
||||
.DS_Store
|
||||
*/**/*un~
|
||||
.vagrant/
|
||||
*.pyc
|
||||
build/
|
||||
pyethash.egg-info/
|
||||
*.so
|
||||
*~
|
||||
*.swp
|
||||
MANIFEST
|
||||
dist/
|
||||
23
Godeps/_workspace/src/github.com/expanse-org/ethash/.travis.yml
generated
vendored
23
Godeps/_workspace/src/github.com/expanse-org/ethash/.travis.yml
generated
vendored
|
|
@ -1,23 +0,0 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.4.2
|
||||
|
||||
before_install:
|
||||
# for g++4.8 and C++11
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
# Set up go-expanse
|
||||
- sudo apt-get update -y -qq
|
||||
- sudo apt-get install -yqq libgmp3-dev
|
||||
- git clone --depth=10 https://github.com/expanse-org/go-expanse ${GOPATH}/src/github.com/expanse-org/go-expanse
|
||||
# use canned dependencies from the go-expanse repository
|
||||
- export GOPATH=$GOPATH:$GOPATH/src/github.com/expanse-org/go-expanse/Godeps/_workspace/
|
||||
- echo $GOPATH
|
||||
|
||||
install:
|
||||
# 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 --yes --force-yes g++-4.8
|
||||
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
|
||||
- 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 valgrind
|
||||
- sudo pip install virtualenv -q
|
||||
script: "./test/test.sh"
|
||||
14
Godeps/_workspace/src/github.com/expanse-org/ethash/CMakeLists.txt
generated
vendored
14
Godeps/_workspace/src/github.com/expanse-org/ethash/CMakeLists.txt
generated
vendored
|
|
@ -1,14 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.8.7)
|
||||
project(ethash)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
|
||||
set(ETHHASH_LIBS ethash)
|
||||
|
||||
if (WIN32 AND WANT_CRYPTOPP)
|
||||
add_subdirectory(cryptopp)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src/libethash)
|
||||
|
||||
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(test/c)
|
||||
17
Godeps/_workspace/src/github.com/expanse-org/ethash/MANIFEST.in
generated
vendored
17
Godeps/_workspace/src/github.com/expanse-org/ethash/MANIFEST.in
generated
vendored
|
|
@ -1,17 +0,0 @@
|
|||
include setup.py
|
||||
|
||||
# C sources
|
||||
include src/libethash/internal.c
|
||||
include src/libethash/sha3.c
|
||||
include src/libethash/util.c
|
||||
include src/python/core.c
|
||||
|
||||
# Headers
|
||||
include src/libethash/compiler.h
|
||||
include src/libethash/data_sizes.h
|
||||
include src/libethash/endian.h
|
||||
include src/libethash/ethash.h
|
||||
include src/libethash/fnv.h
|
||||
include src/libethash/internal.h
|
||||
include src/libethash/sha3.h
|
||||
include src/libethash/util.h
|
||||
6
Godeps/_workspace/src/github.com/expanse-org/ethash/Makefile
generated
vendored
6
Godeps/_workspace/src/github.com/expanse-org/ethash/Makefile
generated
vendored
|
|
@ -1,6 +0,0 @@
|
|||
.PHONY: clean test
|
||||
test:
|
||||
./test/test.sh
|
||||
|
||||
clean:
|
||||
rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash.so test/python/*.pyc dist/ MANIFEST
|
||||
22
Godeps/_workspace/src/github.com/expanse-org/ethash/README.md
generated
vendored
22
Godeps/_workspace/src/github.com/expanse-org/ethash/README.md
generated
vendored
|
|
@ -1,22 +0,0 @@
|
|||
[](https://travis-ci.org/expanse/ethash)
|
||||
[](https://ci.appveyor.com/project/debris/ethash-nr37r/branch/master)
|
||||
|
||||
# Ethash
|
||||
|
||||
For details on this project, please see the Expanse wiki:
|
||||
https://github.com/expanse-org/wiki/wiki/Ethash
|
||||
|
||||
### Coding Style for C++ code:
|
||||
|
||||
Follow the same exact style as in [cpp-expanse](https://github.com/expanse-org/cpp-expanse/blob/develop/CodingStandards.txt)
|
||||
|
||||
### Coding Style for C code:
|
||||
|
||||
The main thing above all is code consistency.
|
||||
|
||||
- Tabs for indentation. A tab is 4 spaces
|
||||
- Try to stick to the [K&R](http://en.wikipedia.org/wiki/Indent_style#K.26R_style),
|
||||
especially for the C code.
|
||||
- Keep the line lengths reasonable. No hard limit on 80 characters but don't go further
|
||||
than 110. Some people work with multiple buffers next to each other.
|
||||
Make them like you :)
|
||||
7
Godeps/_workspace/src/github.com/expanse-org/ethash/Vagrantfile
generated
vendored
7
Godeps/_workspace/src/github.com/expanse-org/ethash/Vagrantfile
generated
vendored
|
|
@ -1,7 +0,0 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.box = "Ubuntu 12.04"
|
||||
config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box"
|
||||
end
|
||||
43
Godeps/_workspace/src/github.com/expanse-org/ethash/appveyor.yml
generated
vendored
43
Godeps/_workspace/src/github.com/expanse-org/ethash/appveyor.yml
generated
vendored
|
|
@ -1,43 +0,0 @@
|
|||
version: 1.0.0.{build}
|
||||
|
||||
environment:
|
||||
BOOST_ROOT: "c:/projects/ethash/deps/boost"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
|
||||
os: Windows Server 2012 R2
|
||||
|
||||
clone_folder: c:\projects\ethash
|
||||
|
||||
#platform: Any CPU
|
||||
#configuration: Debug
|
||||
|
||||
install:
|
||||
# by default, all script lines are interpreted as batch
|
||||
|
||||
# scripts to run before build
|
||||
before_build:
|
||||
- echo "Downloading boost..."
|
||||
- mkdir c:\projects\ethash\deps
|
||||
- cd c:\projects\ethash\deps
|
||||
- curl -O https://build.ethdev.com/builds/windows-precompiled/boost.tar.gz
|
||||
- echo "Unzipping boost..."
|
||||
- 7z x boost.tar.gz > nul
|
||||
- 7z x boost.tar > nul
|
||||
- ls
|
||||
- echo "Running cmake..."
|
||||
- cd c:\projects\ethash
|
||||
- cmake .
|
||||
|
||||
build:
|
||||
project: ALL_BUILD.vcxproj # path to Visual Studio solution or project
|
||||
|
||||
after_build:
|
||||
- echo "Running tests..."
|
||||
- cd c:\projects\ethash\test\c\Debug
|
||||
- Test.exe
|
||||
- echo "Finished!"
|
||||
|
||||
161
Godeps/_workspace/src/github.com/expanse-org/ethash/cmake/modules/CMakeParseArguments.cmake
generated
vendored
161
Godeps/_workspace/src/github.com/expanse-org/ethash/cmake/modules/CMakeParseArguments.cmake
generated
vendored
|
|
@ -1,161 +0,0 @@
|
|||
#.rst:
|
||||
# CMakeParseArguments
|
||||
# -------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords>
|
||||
# <multi_value_keywords> args...)
|
||||
#
|
||||
# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions
|
||||
# for parsing the arguments given to that macro or function. It
|
||||
# processes the arguments and defines a set of variables which hold the
|
||||
# values of the respective options.
|
||||
#
|
||||
# The <options> argument contains all options for the respective macro,
|
||||
# i.e. keywords which can be used when calling the macro without any
|
||||
# value following, like e.g. the OPTIONAL keyword of the install()
|
||||
# command.
|
||||
#
|
||||
# The <one_value_keywords> argument contains all keywords for this macro
|
||||
# which are followed by one value, like e.g. DESTINATION keyword of the
|
||||
# install() command.
|
||||
#
|
||||
# The <multi_value_keywords> argument contains all keywords for this
|
||||
# macro which can be followed by more than one value, like e.g. the
|
||||
# TARGETS or FILES keywords of the install() command.
|
||||
#
|
||||
# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
|
||||
# keywords listed in <options>, <one_value_keywords> and
|
||||
# <multi_value_keywords> a variable composed of the given <prefix>
|
||||
# followed by "_" and the name of the respective keyword. These
|
||||
# variables will then hold the respective value from the argument list.
|
||||
# For the <options> keywords this will be TRUE or FALSE.
|
||||
#
|
||||
# All remaining arguments are collected in a variable
|
||||
# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see
|
||||
# whether your macro was called with unrecognized parameters.
|
||||
#
|
||||
# As an example here a my_install() macro, which takes similar arguments
|
||||
# as the real install() command:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# function(MY_INSTALL)
|
||||
# set(options OPTIONAL FAST)
|
||||
# set(oneValueArgs DESTINATION RENAME)
|
||||
# set(multiValueArgs TARGETS CONFIGURATIONS)
|
||||
# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
|
||||
# "${multiValueArgs}" ${ARGN} )
|
||||
# ...
|
||||
#
|
||||
#
|
||||
#
|
||||
# Assume my_install() has been called like this:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
|
||||
#
|
||||
#
|
||||
#
|
||||
# After the cmake_parse_arguments() call the macro will have set the
|
||||
# following variables:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# MY_INSTALL_OPTIONAL = TRUE
|
||||
# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
|
||||
# MY_INSTALL_DESTINATION = "bin"
|
||||
# MY_INSTALL_RENAME = "" (was not used)
|
||||
# MY_INSTALL_TARGETS = "foo;bar"
|
||||
# MY_INSTALL_CONFIGURATIONS = "" (was not used)
|
||||
# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
|
||||
#
|
||||
#
|
||||
#
|
||||
# You can then continue and process these variables.
|
||||
#
|
||||
# Keywords terminate lists of values, e.g. if directly after a
|
||||
# one_value_keyword another recognized keyword follows, this is
|
||||
# interpreted as the beginning of the new option. E.g.
|
||||
# my_install(TARGETS foo DESTINATION OPTIONAL) would result in
|
||||
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION
|
||||
# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
|
||||
if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
|
||||
return()
|
||||
endif()
|
||||
set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
|
||||
|
||||
|
||||
function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
|
||||
# first set all result variables to empty/FALSE
|
||||
foreach(arg_name ${_singleArgNames} ${_multiArgNames})
|
||||
set(${prefix}_${arg_name})
|
||||
endforeach()
|
||||
|
||||
foreach(option ${_optionNames})
|
||||
set(${prefix}_${option} FALSE)
|
||||
endforeach()
|
||||
|
||||
set(${prefix}_UNPARSED_ARGUMENTS)
|
||||
|
||||
set(insideValues FALSE)
|
||||
set(currentArgName)
|
||||
|
||||
# now iterate over all arguments and fill the result variables
|
||||
foreach(currentArg ${ARGN})
|
||||
list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
|
||||
if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1)
|
||||
if(insideValues)
|
||||
if("${insideValues}" STREQUAL "SINGLE")
|
||||
set(${prefix}_${currentArgName} ${currentArg})
|
||||
set(insideValues FALSE)
|
||||
elseif("${insideValues}" STREQUAL "MULTI")
|
||||
list(APPEND ${prefix}_${currentArgName} ${currentArg})
|
||||
endif()
|
||||
else()
|
||||
list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
|
||||
endif()
|
||||
else()
|
||||
if(NOT ${optionIndex} EQUAL -1)
|
||||
set(${prefix}_${currentArg} TRUE)
|
||||
set(insideValues FALSE)
|
||||
elseif(NOT ${singleArgIndex} EQUAL -1)
|
||||
set(currentArgName ${currentArg})
|
||||
set(${prefix}_${currentArgName})
|
||||
set(insideValues "SINGLE")
|
||||
elseif(NOT ${multiArgIndex} EQUAL -1)
|
||||
set(currentArgName ${currentArg})
|
||||
set(${prefix}_${currentArgName})
|
||||
set(insideValues "MULTI")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endforeach()
|
||||
|
||||
# propagate the result variables to the caller:
|
||||
foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
|
||||
set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE)
|
||||
endforeach()
|
||||
set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
|
||||
|
||||
endfunction()
|
||||
108
Godeps/_workspace/src/github.com/expanse-org/ethash/cmake/modules/FindCryptoPP.cmake
generated
vendored
108
Godeps/_workspace/src/github.com/expanse-org/ethash/cmake/modules/FindCryptoPP.cmake
generated
vendored
|
|
@ -1,108 +0,0 @@
|
|||
# Module for locating the Crypto++ encryption library.
|
||||
#
|
||||
# Customizable variables:
|
||||
# CRYPTOPP_ROOT_DIR
|
||||
# This variable points to the CryptoPP root directory. On Windows the
|
||||
# library location typically will have to be provided explicitly using the
|
||||
# -D command-line option. The directory should include the include/cryptopp,
|
||||
# lib and/or bin sub-directories.
|
||||
#
|
||||
# Read-only variables:
|
||||
# CRYPTOPP_FOUND
|
||||
# Indicates whether the library has been found.
|
||||
#
|
||||
# CRYPTOPP_INCLUDE_DIRS
|
||||
# Points to the CryptoPP include directory.
|
||||
#
|
||||
# CRYPTOPP_LIBRARIES
|
||||
# Points to the CryptoPP libraries that should be passed to
|
||||
# target_link_libararies.
|
||||
#
|
||||
#
|
||||
# Copyright (c) 2012 Sergiu Dotenco
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
INCLUDE (FindPackageHandleStandardArgs)
|
||||
|
||||
FIND_PATH (CRYPTOPP_ROOT_DIR
|
||||
NAMES cryptopp/cryptlib.h include/cryptopp/cryptlib.h
|
||||
PATHS ENV CRYPTOPPROOT
|
||||
DOC "CryptoPP root directory")
|
||||
|
||||
# Re-use the previous path:
|
||||
FIND_PATH (CRYPTOPP_INCLUDE_DIR
|
||||
NAMES cryptopp/cryptlib.h
|
||||
HINTS ${CRYPTOPP_ROOT_DIR}
|
||||
PATH_SUFFIXES include
|
||||
DOC "CryptoPP include directory")
|
||||
|
||||
FIND_LIBRARY (CRYPTOPP_LIBRARY_DEBUG
|
||||
NAMES cryptlibd cryptoppd
|
||||
HINTS ${CRYPTOPP_ROOT_DIR}
|
||||
PATH_SUFFIXES lib
|
||||
DOC "CryptoPP debug library")
|
||||
|
||||
FIND_LIBRARY (CRYPTOPP_LIBRARY_RELEASE
|
||||
NAMES cryptlib cryptopp
|
||||
HINTS ${CRYPTOPP_ROOT_DIR}
|
||||
PATH_SUFFIXES lib
|
||||
DOC "CryptoPP release library")
|
||||
|
||||
IF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE)
|
||||
SET (CRYPTOPP_LIBRARY
|
||||
optimized ${CRYPTOPP_LIBRARY_RELEASE}
|
||||
debug ${CRYPTOPP_LIBRARY_DEBUG} CACHE DOC "CryptoPP library")
|
||||
ELSEIF (CRYPTOPP_LIBRARY_RELEASE)
|
||||
SET (CRYPTOPP_LIBRARY ${CRYPTOPP_LIBRARY_RELEASE} CACHE DOC
|
||||
"CryptoPP library")
|
||||
ENDIF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE)
|
||||
|
||||
IF (CRYPTOPP_INCLUDE_DIR)
|
||||
SET (_CRYPTOPP_VERSION_HEADER ${CRYPTOPP_INCLUDE_DIR}/cryptopp/config.h)
|
||||
|
||||
IF (EXISTS ${_CRYPTOPP_VERSION_HEADER})
|
||||
FILE (STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION_TMP REGEX
|
||||
"^#define CRYPTOPP_VERSION[ \t]+[0-9]+$")
|
||||
|
||||
STRING (REGEX REPLACE
|
||||
"^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION_TMP
|
||||
${_CRYPTOPP_VERSION_TMP})
|
||||
|
||||
STRING (REGEX REPLACE "([0-9]+)[0-9][0-9]" "\\1" CRYPTOPP_VERSION_MAJOR
|
||||
${_CRYPTOPP_VERSION_TMP})
|
||||
STRING (REGEX REPLACE "[0-9]([0-9])[0-9]" "\\1" CRYPTOPP_VERSION_MINOR
|
||||
${_CRYPTOPP_VERSION_TMP})
|
||||
STRING (REGEX REPLACE "[0-9][0-9]([0-9])" "\\1" CRYPTOPP_VERSION_PATCH
|
||||
${_CRYPTOPP_VERSION_TMP})
|
||||
|
||||
SET (CRYPTOPP_VERSION_COUNT 3)
|
||||
SET (CRYPTOPP_VERSION
|
||||
${CRYPTOPP_VERSION_MAJOR}.${CRYPTOPP_VERSION_MINOR}.${CRYPTOPP_VERSION_PATCH})
|
||||
ENDIF (EXISTS ${_CRYPTOPP_VERSION_HEADER})
|
||||
ENDIF (CRYPTOPP_INCLUDE_DIR)
|
||||
|
||||
SET (CRYPTOPP_INCLUDE_DIRS ${CRYPTOPP_INCLUDE_DIR})
|
||||
SET (CRYPTOPP_LIBRARIES ${CRYPTOPP_LIBRARY})
|
||||
|
||||
MARK_AS_ADVANCED (CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY CRYPTOPP_LIBRARY_DEBUG
|
||||
CRYPTOPP_LIBRARY_RELEASE)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS (CryptoPP REQUIRED_VARS CRYPTOPP_ROOT_DIR
|
||||
CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY VERSION_VAR CRYPTOPP_VERSION)
|
||||
148
Godeps/_workspace/src/github.com/expanse-org/ethash/cmake/modules/FindOpenCL.cmake
generated
vendored
148
Godeps/_workspace/src/github.com/expanse-org/ethash/cmake/modules/FindOpenCL.cmake
generated
vendored
|
|
@ -1,148 +0,0 @@
|
|||
#.rst:
|
||||
# FindOpenCL
|
||||
# ----------
|
||||
#
|
||||
# Try to find OpenCL
|
||||
#
|
||||
# Once done this will define::
|
||||
#
|
||||
# OpenCL_FOUND - True if OpenCL was found
|
||||
# OpenCL_INCLUDE_DIRS - include directories for OpenCL
|
||||
# OpenCL_LIBRARIES - link against this library to use OpenCL
|
||||
# OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2)
|
||||
# OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation
|
||||
# OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation
|
||||
#
|
||||
# The module will also define two cache variables::
|
||||
#
|
||||
# OpenCL_INCLUDE_DIR - the OpenCL include directory
|
||||
# OpenCL_LIBRARY - the path to the OpenCL library
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2014 Matthaeus G. Chajdas
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function(_FIND_OPENCL_VERSION)
|
||||
include(CheckSymbolExists)
|
||||
include(CMakePushCheckState)
|
||||
set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY})
|
||||
|
||||
CMAKE_PUSH_CHECK_STATE()
|
||||
foreach(VERSION "2_0" "1_2" "1_1" "1_0")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}")
|
||||
|
||||
if(APPLE)
|
||||
CHECK_SYMBOL_EXISTS(
|
||||
CL_VERSION_${VERSION}
|
||||
"${OpenCL_INCLUDE_DIR}/OpenCL/cl.h"
|
||||
OPENCL_VERSION_${VERSION})
|
||||
else()
|
||||
CHECK_SYMBOL_EXISTS(
|
||||
CL_VERSION_${VERSION}
|
||||
"${OpenCL_INCLUDE_DIR}/CL/cl.h"
|
||||
OPENCL_VERSION_${VERSION})
|
||||
endif()
|
||||
|
||||
if(OPENCL_VERSION_${VERSION})
|
||||
string(REPLACE "_" "." VERSION "${VERSION}")
|
||||
set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE)
|
||||
string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}")
|
||||
list(GET version_components 0 major_version)
|
||||
list(GET version_components 1 minor_version)
|
||||
set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE)
|
||||
set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
CMAKE_POP_CHECK_STATE()
|
||||
endfunction()
|
||||
|
||||
find_path(OpenCL_INCLUDE_DIR
|
||||
NAMES
|
||||
CL/cl.h OpenCL/cl.h
|
||||
PATHS
|
||||
ENV "PROGRAMFILES(X86)"
|
||||
ENV AMDAPPSDKROOT
|
||||
ENV INTELOCLSDKROOT
|
||||
ENV NVSDKCOMPUTE_ROOT
|
||||
ENV CUDA_PATH
|
||||
ENV ATISTREAMSDKROOT
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
OpenCL/common/inc
|
||||
"AMD APP/include")
|
||||
|
||||
_FIND_OPENCL_VERSION()
|
||||
|
||||
if(WIN32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
find_library(OpenCL_LIBRARY
|
||||
NAMES OpenCL
|
||||
PATHS
|
||||
ENV "PROGRAMFILES(X86)"
|
||||
ENV AMDAPPSDKROOT
|
||||
ENV INTELOCLSDKROOT
|
||||
ENV CUDA_PATH
|
||||
ENV NVSDKCOMPUTE_ROOT
|
||||
ENV ATISTREAMSDKROOT
|
||||
PATH_SUFFIXES
|
||||
"AMD APP/lib/x86"
|
||||
lib/x86
|
||||
lib/Win32
|
||||
OpenCL/common/lib/Win32)
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
find_library(OpenCL_LIBRARY
|
||||
NAMES OpenCL
|
||||
PATHS
|
||||
ENV "PROGRAMFILES(X86)"
|
||||
ENV AMDAPPSDKROOT
|
||||
ENV INTELOCLSDKROOT
|
||||
ENV CUDA_PATH
|
||||
ENV NVSDKCOMPUTE_ROOT
|
||||
ENV ATISTREAMSDKROOT
|
||||
PATH_SUFFIXES
|
||||
"AMD APP/lib/x86_64"
|
||||
lib/x86_64
|
||||
lib/x64
|
||||
OpenCL/common/lib/x64)
|
||||
endif()
|
||||
else()
|
||||
find_library(OpenCL_LIBRARY
|
||||
NAMES OpenCL
|
||||
PATHS
|
||||
ENV "PROGRAMFILES(X86)"
|
||||
ENV AMDAPPSDKROOT
|
||||
ENV INTELOCLSDKROOT
|
||||
ENV CUDA_PATH
|
||||
ENV NVSDKCOMPUTE_ROOT
|
||||
ENV ATISTREAMSDKROOT
|
||||
PATH_SUFFIXES
|
||||
"AMD APP/lib/x86_64"
|
||||
lib/x86_64
|
||||
lib/x64
|
||||
OpenCL/common/lib/x64)
|
||||
endif()
|
||||
|
||||
set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})
|
||||
set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR})
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
|
||||
find_package_handle_standard_args(
|
||||
OpenCL
|
||||
FOUND_VAR OpenCL_FOUND
|
||||
REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR
|
||||
VERSION_VAR OpenCL_VERSION_STRING)
|
||||
|
||||
mark_as_advanced(
|
||||
OpenCL_INCLUDE_DIR
|
||||
OpenCL_LIBRARY)
|
||||
|
|
@ -1,382 +0,0 @@
|
|||
#.rst:
|
||||
# FindPackageHandleStandardArgs
|
||||
# -----------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> ... )
|
||||
#
|
||||
# This function is intended to be used in FindXXX.cmake modules files.
|
||||
# It handles the REQUIRED, QUIET and version-related arguments to
|
||||
# find_package(). It also sets the <packagename>_FOUND variable. The
|
||||
# package is considered found if all variables <var1>... listed contain
|
||||
# valid results, e.g. valid filepaths.
|
||||
#
|
||||
# There are two modes of this function. The first argument in both
|
||||
# modes is the name of the Find-module where it is called (in original
|
||||
# casing).
|
||||
#
|
||||
# The first simple mode looks like this:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name>
|
||||
# (DEFAULT_MSG|"Custom failure message") <var1>...<varN> )
|
||||
#
|
||||
# If the variables <var1> to <varN> are all valid, then
|
||||
# <UPPERCASED_NAME>_FOUND will be set to TRUE. If DEFAULT_MSG is given
|
||||
# as second argument, then the function will generate itself useful
|
||||
# success and error messages. You can also supply a custom error
|
||||
# message for the failure case. This is not recommended.
|
||||
#
|
||||
# The second mode is more powerful and also supports version checking:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME
|
||||
# [FOUND_VAR <resultVar>]
|
||||
# [REQUIRED_VARS <var1>...<varN>]
|
||||
# [VERSION_VAR <versionvar>]
|
||||
# [HANDLE_COMPONENTS]
|
||||
# [CONFIG_MODE]
|
||||
# [FAIL_MESSAGE "Custom failure message"] )
|
||||
#
|
||||
# In this mode, the name of the result-variable can be set either to
|
||||
# either <UPPERCASED_NAME>_FOUND or <OriginalCase_Name>_FOUND using the
|
||||
# FOUND_VAR option. Other names for the result-variable are not
|
||||
# allowed. So for a Find-module named FindFooBar.cmake, the two
|
||||
# possible names are FooBar_FOUND and FOOBAR_FOUND. It is recommended
|
||||
# to use the original case version. If the FOUND_VAR option is not
|
||||
# used, the default is <UPPERCASED_NAME>_FOUND.
|
||||
#
|
||||
# As in the simple mode, if <var1> through <varN> are all valid,
|
||||
# <packagename>_FOUND will be set to TRUE. After REQUIRED_VARS the
|
||||
# variables which are required for this package are listed. Following
|
||||
# VERSION_VAR the name of the variable can be specified which holds the
|
||||
# version of the package which has been found. If this is done, this
|
||||
# version will be checked against the (potentially) specified required
|
||||
# version used in the find_package() call. The EXACT keyword is also
|
||||
# handled. The default messages include information about the required
|
||||
# version and the version which has been actually found, both if the
|
||||
# version is ok or not. If the package supports components, use the
|
||||
# HANDLE_COMPONENTS option to enable handling them. In this case,
|
||||
# find_package_handle_standard_args() will report which components have
|
||||
# been found and which are missing, and the <packagename>_FOUND variable
|
||||
# will be set to FALSE if any of the required components (i.e. not the
|
||||
# ones listed after OPTIONAL_COMPONENTS) are missing. Use the option
|
||||
# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a
|
||||
# find_package(... NO_MODULE) call. In this case VERSION_VAR will be
|
||||
# set to <NAME>_VERSION and the macro will automatically check whether
|
||||
# the Config module was found. Via FAIL_MESSAGE a custom failure
|
||||
# message can be specified, if this is not used, the default message
|
||||
# will be displayed.
|
||||
#
|
||||
# Example for mode 1:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# find_package_handle_standard_args(LibXml2 DEFAULT_MSG
|
||||
# LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
|
||||
#
|
||||
#
|
||||
#
|
||||
# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and
|
||||
# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to
|
||||
# TRUE. If it is not found and REQUIRED was used, it fails with
|
||||
# FATAL_ERROR, independent whether QUIET was used or not. If it is
|
||||
# found, success will be reported, including the content of <var1>. On
|
||||
# repeated Cmake runs, the same message won't be printed again.
|
||||
#
|
||||
# Example for mode 2:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# find_package_handle_standard_args(LibXslt
|
||||
# FOUND_VAR LibXslt_FOUND
|
||||
# REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS
|
||||
# VERSION_VAR LibXslt_VERSION_STRING)
|
||||
#
|
||||
# In this case, LibXslt is considered to be found if the variable(s)
|
||||
# listed after REQUIRED_VAR are all valid, i.e. LibXslt_LIBRARIES and
|
||||
# LibXslt_INCLUDE_DIRS in this case. The result will then be stored in
|
||||
# LibXslt_FOUND . Also the version of LibXslt will be checked by using
|
||||
# the version contained in LibXslt_VERSION_STRING. Since no
|
||||
# FAIL_MESSAGE is given, the default messages will be printed.
|
||||
#
|
||||
# Another example for mode 2:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
|
||||
# find_package_handle_standard_args(Automoc4 CONFIG_MODE)
|
||||
#
|
||||
# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4
|
||||
# NO_MODULE) and adds an additional search directory for automoc4. Here
|
||||
# the result will be stored in AUTOMOC4_FOUND. The following
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper
|
||||
# success/error message.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2007-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake)
|
||||
|
||||
# internal helper macro
|
||||
macro(_FPHSA_FAILURE_MESSAGE _msg)
|
||||
if (${_NAME}_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "${_msg}")
|
||||
else ()
|
||||
if (NOT ${_NAME}_FIND_QUIETLY)
|
||||
message(STATUS "${_msg}")
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
|
||||
# internal helper macro to generate the failure message when used in CONFIG_MODE:
|
||||
macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
|
||||
# <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
|
||||
if(${_NAME}_CONFIG)
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
|
||||
else()
|
||||
# If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
|
||||
# List them all in the error message:
|
||||
if(${_NAME}_CONSIDERED_CONFIGS)
|
||||
set(configsText "")
|
||||
list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
|
||||
math(EXPR configsCount "${configsCount} - 1")
|
||||
foreach(currentConfigIndex RANGE ${configsCount})
|
||||
list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
|
||||
list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
|
||||
set(configsText "${configsText} ${filename} (version ${version})\n")
|
||||
endforeach()
|
||||
if (${_NAME}_NOT_FOUND_MESSAGE)
|
||||
set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n")
|
||||
endif()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
|
||||
|
||||
else()
|
||||
# Simple case: No Config-file was found at all:
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
|
||||
|
||||
# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
|
||||
# new extended or in the "old" mode:
|
||||
set(options CONFIG_MODE HANDLE_COMPONENTS)
|
||||
set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR)
|
||||
set(multiValueArgs REQUIRED_VARS)
|
||||
set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
|
||||
list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
|
||||
|
||||
if(${INDEX} EQUAL -1)
|
||||
set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
|
||||
set(FPHSA_REQUIRED_VARS ${ARGN})
|
||||
set(FPHSA_VERSION_VAR)
|
||||
else()
|
||||
|
||||
CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
|
||||
|
||||
if(FPHSA_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
|
||||
endif()
|
||||
|
||||
if(NOT FPHSA_FAIL_MESSAGE)
|
||||
set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# now that we collected all arguments, process them
|
||||
|
||||
if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
|
||||
set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
|
||||
endif()
|
||||
|
||||
# In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
|
||||
# when it successfully found the config-file, including version checking:
|
||||
if(FPHSA_CONFIG_MODE)
|
||||
list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
|
||||
list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
|
||||
set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
|
||||
endif()
|
||||
|
||||
if(NOT FPHSA_REQUIRED_VARS)
|
||||
message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
|
||||
endif()
|
||||
|
||||
list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
|
||||
|
||||
string(TOUPPER ${_NAME} _NAME_UPPER)
|
||||
string(TOLOWER ${_NAME} _NAME_LOWER)
|
||||
|
||||
if(FPHSA_FOUND_VAR)
|
||||
if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
|
||||
set(_FOUND_VAR ${FPHSA_FOUND_VAR})
|
||||
else()
|
||||
message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
|
||||
endif()
|
||||
else()
|
||||
set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
|
||||
endif()
|
||||
|
||||
# collect all variables which were not found, so they can be printed, so the
|
||||
# user knows better what went wrong (#6375)
|
||||
set(MISSING_VARS "")
|
||||
set(DETAILS "")
|
||||
# check if all passed variables are valid
|
||||
unset(${_FOUND_VAR})
|
||||
foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
|
||||
if(NOT ${_CURRENT_VAR})
|
||||
set(${_FOUND_VAR} FALSE)
|
||||
set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
|
||||
else()
|
||||
set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
|
||||
endif()
|
||||
endforeach()
|
||||
if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE")
|
||||
set(${_FOUND_VAR} TRUE)
|
||||
endif()
|
||||
|
||||
# component handling
|
||||
unset(FOUND_COMPONENTS_MSG)
|
||||
unset(MISSING_COMPONENTS_MSG)
|
||||
|
||||
if(FPHSA_HANDLE_COMPONENTS)
|
||||
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||
if(${_NAME}_${comp}_FOUND)
|
||||
|
||||
if(NOT DEFINED FOUND_COMPONENTS_MSG)
|
||||
set(FOUND_COMPONENTS_MSG "found components: ")
|
||||
endif()
|
||||
set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}")
|
||||
|
||||
else()
|
||||
|
||||
if(NOT DEFINED MISSING_COMPONENTS_MSG)
|
||||
set(MISSING_COMPONENTS_MSG "missing components: ")
|
||||
endif()
|
||||
set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}")
|
||||
|
||||
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||
set(${_FOUND_VAR} FALSE)
|
||||
set(MISSING_VARS "${MISSING_VARS} ${comp}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endforeach()
|
||||
set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
|
||||
set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]")
|
||||
endif()
|
||||
|
||||
# version handling:
|
||||
set(VERSION_MSG "")
|
||||
set(VERSION_OK TRUE)
|
||||
set(VERSION ${${FPHSA_VERSION_VAR}})
|
||||
|
||||
# check with DEFINED here as the requested or found version may be "0"
|
||||
if (DEFINED ${_NAME}_FIND_VERSION)
|
||||
if(DEFINED ${FPHSA_VERSION_VAR})
|
||||
|
||||
if(${_NAME}_FIND_VERSION_EXACT) # exact version required
|
||||
# count the dots in the version string
|
||||
string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}")
|
||||
# add one dot because there is one dot more than there are components
|
||||
string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS)
|
||||
if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT)
|
||||
# Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT
|
||||
# is at most 4 here. Therefore a simple lookup table is used.
|
||||
if (${_NAME}_FIND_VERSION_COUNT EQUAL 1)
|
||||
set(_VERSION_REGEX "[^.]*")
|
||||
elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2)
|
||||
set(_VERSION_REGEX "[^.]*\\.[^.]*")
|
||||
elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3)
|
||||
set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*")
|
||||
else ()
|
||||
set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
|
||||
endif ()
|
||||
string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}")
|
||||
unset(_VERSION_REGEX)
|
||||
if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD)
|
||||
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
|
||||
set(VERSION_OK FALSE)
|
||||
else ()
|
||||
set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
|
||||
endif ()
|
||||
unset(_VERSION_HEAD)
|
||||
else ()
|
||||
if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
|
||||
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
|
||||
set(VERSION_OK FALSE)
|
||||
else ()
|
||||
set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
|
||||
endif ()
|
||||
endif ()
|
||||
unset(_VERSION_DOTS)
|
||||
|
||||
else() # minimum version specified:
|
||||
if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
|
||||
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
|
||||
set(VERSION_OK FALSE)
|
||||
else ()
|
||||
set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
else()
|
||||
|
||||
# if the package was not found, but a version was given, add that to the output:
|
||||
if(${_NAME}_FIND_VERSION_EXACT)
|
||||
set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
|
||||
else()
|
||||
set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
else ()
|
||||
if(VERSION)
|
||||
set(VERSION_MSG "(found version \"${VERSION}\")")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if(VERSION_OK)
|
||||
set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
|
||||
else()
|
||||
set(${_FOUND_VAR} FALSE)
|
||||
endif()
|
||||
|
||||
|
||||
# print the result:
|
||||
if (${_FOUND_VAR})
|
||||
FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
|
||||
else ()
|
||||
|
||||
if(FPHSA_CONFIG_MODE)
|
||||
_FPHSA_HANDLE_FAILURE_CONFIG_MODE()
|
||||
else()
|
||||
if(NOT VERSION_OK)
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
|
||||
else()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif ()
|
||||
|
||||
set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE)
|
||||
|
||||
endfunction()
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#.rst:
|
||||
# FindPackageMessage
|
||||
# ------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
# FIND_PACKAGE_MESSAGE(<name> "message for user" "find result details")
|
||||
#
|
||||
# This macro is intended to be used in FindXXX.cmake modules files. It
|
||||
# will print a message once for each unique find result. This is useful
|
||||
# for telling the user where a package was found. The first argument
|
||||
# specifies the name (XXX) of the package. The second argument
|
||||
# specifies the message to display. The third argument lists details
|
||||
# about the find result so that if they change the message will be
|
||||
# displayed again. The macro also obeys the QUIET argument to the
|
||||
# find_package command.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# if(X11_FOUND)
|
||||
# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}"
|
||||
# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
|
||||
# else()
|
||||
# ...
|
||||
# endif()
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2008-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function(FIND_PACKAGE_MESSAGE pkg msg details)
|
||||
# Avoid printing a message repeatedly for the same find result.
|
||||
if(NOT ${pkg}_FIND_QUIETLY)
|
||||
string(REPLACE "\n" "" details "${details}")
|
||||
set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
|
||||
if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
|
||||
# The message has not yet been printed.
|
||||
message(STATUS "${msg}")
|
||||
|
||||
# Save the find details in the cache to avoid printing the same
|
||||
# message again.
|
||||
set("${DETAILS_VAR}" "${details}"
|
||||
CACHE INTERNAL "Details about finding ${pkg}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
13
Godeps/_workspace/src/github.com/expanse-org/ethash/cryptopp/CMakeLists.txt
generated
vendored
13
Godeps/_workspace/src/github.com/expanse-org/ethash/cryptopp/CMakeLists.txt
generated
vendored
|
|
@ -1,13 +0,0 @@
|
|||
set(LIBRARY cryptopp)
|
||||
|
||||
include_directories(../../cryptopp)
|
||||
|
||||
# todo, subset
|
||||
file(GLOB HEADERS "../../cryptopp/*.h")
|
||||
file(GLOB SOURCE "../../cryptopp/*.cpp")
|
||||
|
||||
add_library(${LIBRARY} ${HEADERS} ${SOURCE})
|
||||
|
||||
set(CRYPTOPP_INCLUDE_DIRS "../.." "../../../" PARENT_SCOPE)
|
||||
set(CRYPTOPP_LIBRARIES ${LIBRARY} PARENT_SCOPE)
|
||||
set(CRYPTOPP_FOUND TRUE PARENT_SCOPE)
|
||||
441
Godeps/_workspace/src/github.com/expanse-org/ethash/ethash.go
generated
vendored
441
Godeps/_workspace/src/github.com/expanse-org/ethash/ethash.go
generated
vendored
|
|
@ -1,441 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// Copyright 2015 Lefteris Karapetsas <lefteris@refu.co>
|
||||
// Copyright 2015 Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ethash
|
||||
|
||||
/*
|
||||
#include "src/libethash/internal.h"
|
||||
|
||||
int ethashGoCallback_cgo(unsigned);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/logger"
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
"github.com/expanse-org/go-expanse/pow"
|
||||
)
|
||||
|
||||
var (
|
||||
maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
|
||||
sharedLight = new(Light)
|
||||
)
|
||||
|
||||
const (
|
||||
epochLength uint64 = 30000
|
||||
cacheSizeForTesting C.uint64_t = 1024
|
||||
dagSizeForTesting C.uint64_t = 1024 * 32
|
||||
)
|
||||
|
||||
var DefaultDir = defaultDir()
|
||||
|
||||
func defaultDir() string {
|
||||
home := os.Getenv("HOME")
|
||||
if user, err := user.Current(); err == nil {
|
||||
home = user.HomeDir
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
return filepath.Join(home, "AppData", "Ethash")
|
||||
}
|
||||
return filepath.Join(home, ".ethash")
|
||||
}
|
||||
|
||||
// cache wraps an ethash_light_t with some metadata
|
||||
// and automatic memory management.
|
||||
type cache struct {
|
||||
epoch uint64
|
||||
used time.Time
|
||||
test bool
|
||||
|
||||
gen sync.Once // ensures cache is only generated once.
|
||||
ptr *C.struct_ethash_light
|
||||
}
|
||||
|
||||
// generate creates the actual cache. it can be called from multiple
|
||||
// goroutines. the first call will generate the cache, subsequent
|
||||
// calls wait until it is generated.
|
||||
func (cache *cache) generate() {
|
||||
cache.gen.Do(func() {
|
||||
started := time.Now()
|
||||
seedHash := makeSeedHash(cache.epoch)
|
||||
glog.V(logger.Debug).Infof("Generating cache for epoch %d (%x)", cache.epoch, seedHash)
|
||||
size := C.ethash_get_cachesize(C.uint64_t(cache.epoch * epochLength))
|
||||
if cache.test {
|
||||
size = cacheSizeForTesting
|
||||
}
|
||||
cache.ptr = C.ethash_light_new_internal(size, (*C.ethash_h256_t)(unsafe.Pointer(&seedHash[0])))
|
||||
runtime.SetFinalizer(cache, freeCache)
|
||||
glog.V(logger.Debug).Infof("Done generating cache for epoch %d, it took %v", cache.epoch, time.Since(started))
|
||||
})
|
||||
}
|
||||
|
||||
func freeCache(cache *cache) {
|
||||
C.ethash_light_delete(cache.ptr)
|
||||
cache.ptr = nil
|
||||
}
|
||||
|
||||
func (cache *cache) compute(dagSize uint64, hash common.Hash, nonce uint64) (ok bool, mixDigest, result common.Hash) {
|
||||
ret := C.ethash_light_compute_internal(cache.ptr, C.uint64_t(dagSize), hashToH256(hash), C.uint64_t(nonce))
|
||||
// Make sure cache is live until after the C call.
|
||||
// This is important because a GC might happen and execute
|
||||
// the finalizer before the call completes.
|
||||
_ = cache
|
||||
return bool(ret.success), h256ToHash(ret.mix_hash), h256ToHash(ret.result)
|
||||
}
|
||||
|
||||
// Light implements the Verify half of the proof of work. It uses a few small
|
||||
// in-memory caches to verify the nonces found by Full.
|
||||
type Light struct {
|
||||
test bool // If set, use a smaller cache size
|
||||
|
||||
mu sync.Mutex // Protects the per-epoch map of verification caches
|
||||
caches map[uint64]*cache // Currently maintained verification caches
|
||||
future *cache // Pre-generated cache for the estimated future DAG
|
||||
|
||||
NumCaches int // Maximum number of caches to keep before eviction (only init, don't modify)
|
||||
}
|
||||
|
||||
// Verify checks whether the block's nonce is valid.
|
||||
func (l *Light) Verify(block pow.Block) bool {
|
||||
// TODO: do ethash_quick_verify before getCache in order
|
||||
// to prevent DOS attacks.
|
||||
blockNum := block.NumberU64()
|
||||
if blockNum >= epochLength*2048 {
|
||||
glog.V(logger.Debug).Infof("block number %d too high, limit is %d", epochLength*2048)
|
||||
return false
|
||||
}
|
||||
|
||||
difficulty := block.Difficulty()
|
||||
/* Cannot happen if block header diff is validated prior to PoW, but can
|
||||
happen if PoW is checked first due to parallel PoW checking.
|
||||
We could check the minimum valid difficulty but for SoC we avoid (duplicating)
|
||||
Expanse protocol consensus rules here which are not in scope of Ethash
|
||||
*/
|
||||
if difficulty.Cmp(common.Big0) == 0 {
|
||||
glog.V(logger.Debug).Infof("invalid block difficulty")
|
||||
return false
|
||||
}
|
||||
|
||||
cache := l.getCache(blockNum)
|
||||
dagSize := C.ethash_get_datasize(C.uint64_t(blockNum))
|
||||
if l.test {
|
||||
dagSize = dagSizeForTesting
|
||||
}
|
||||
// Recompute the hash using the cache.
|
||||
ok, mixDigest, result := cache.compute(uint64(dagSize), block.HashNoNonce(), block.Nonce())
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// avoid mixdigest malleability as it's not included in a block's "hashNononce"
|
||||
if block.MixDigest() != mixDigest {
|
||||
return false
|
||||
}
|
||||
|
||||
// The actual check.
|
||||
target := new(big.Int).Div(maxUint256, difficulty)
|
||||
return result.Big().Cmp(target) <= 0
|
||||
}
|
||||
|
||||
func h256ToHash(in C.ethash_h256_t) common.Hash {
|
||||
return *(*common.Hash)(unsafe.Pointer(&in.b))
|
||||
}
|
||||
|
||||
func hashToH256(in common.Hash) C.ethash_h256_t {
|
||||
return C.ethash_h256_t{b: *(*[32]C.uint8_t)(unsafe.Pointer(&in[0]))}
|
||||
}
|
||||
|
||||
func (l *Light) getCache(blockNum uint64) *cache {
|
||||
var c *cache
|
||||
epoch := blockNum / epochLength
|
||||
|
||||
// If we have a PoW for that epoch, use that
|
||||
l.mu.Lock()
|
||||
if l.caches == nil {
|
||||
l.caches = make(map[uint64]*cache)
|
||||
}
|
||||
if l.NumCaches == 0 {
|
||||
l.NumCaches = 3
|
||||
}
|
||||
c = l.caches[epoch]
|
||||
if c == nil {
|
||||
// No cached DAG, evict the oldest if the cache limit was reached
|
||||
if len(l.caches) >= l.NumCaches {
|
||||
var evict *cache
|
||||
for _, cache := range l.caches {
|
||||
if evict == nil || evict.used.After(cache.used) {
|
||||
evict = cache
|
||||
}
|
||||
}
|
||||
glog.V(logger.Debug).Infof("Evicting DAG for epoch %d in favour of epoch %d", evict.epoch, epoch)
|
||||
delete(l.caches, evict.epoch)
|
||||
}
|
||||
// If we have the new DAG pre-generated, use that, otherwise create a new one
|
||||
if l.future != nil && l.future.epoch == epoch {
|
||||
glog.V(logger.Debug).Infof("Using pre-generated DAG for epoch %d", epoch)
|
||||
c, l.future = l.future, nil
|
||||
} else {
|
||||
glog.V(logger.Debug).Infof("No pre-generated DAG available, creating new for epoch %d", epoch)
|
||||
c = &cache{epoch: epoch, test: l.test}
|
||||
}
|
||||
l.caches[epoch] = c
|
||||
|
||||
// If we just used up the future cache, or need a refresh, regenerate
|
||||
if l.future == nil || l.future.epoch <= epoch {
|
||||
glog.V(logger.Debug).Infof("Pre-generating DAG for epoch %d", epoch+1)
|
||||
l.future = &cache{epoch: epoch + 1, test: l.test}
|
||||
go l.future.generate()
|
||||
}
|
||||
}
|
||||
c.used = time.Now()
|
||||
l.mu.Unlock()
|
||||
|
||||
// Wait for generation finish and return the cache
|
||||
c.generate()
|
||||
return c
|
||||
}
|
||||
|
||||
// dag wraps an ethash_full_t with some metadata
|
||||
// and automatic memory management.
|
||||
type dag struct {
|
||||
epoch uint64
|
||||
test bool
|
||||
dir string
|
||||
|
||||
gen sync.Once // ensures DAG is only generated once.
|
||||
ptr *C.struct_ethash_full
|
||||
}
|
||||
|
||||
// generate creates the actual DAG. it can be called from multiple
|
||||
// goroutines. the first call will generate the DAG, subsequent
|
||||
// calls wait until it is generated.
|
||||
func (d *dag) generate() {
|
||||
d.gen.Do(func() {
|
||||
var (
|
||||
started = time.Now()
|
||||
seedHash = makeSeedHash(d.epoch)
|
||||
blockNum = C.uint64_t(d.epoch * epochLength)
|
||||
cacheSize = C.ethash_get_cachesize(blockNum)
|
||||
dagSize = C.ethash_get_datasize(blockNum)
|
||||
)
|
||||
if d.test {
|
||||
cacheSize = cacheSizeForTesting
|
||||
dagSize = dagSizeForTesting
|
||||
}
|
||||
if d.dir == "" {
|
||||
d.dir = DefaultDir
|
||||
}
|
||||
glog.V(logger.Info).Infof("Generating DAG for epoch %d (size %d) (%x)", d.epoch, dagSize, seedHash)
|
||||
// Generate a temporary cache.
|
||||
// TODO: this could share the cache with Light
|
||||
cache := C.ethash_light_new_internal(cacheSize, (*C.ethash_h256_t)(unsafe.Pointer(&seedHash[0])))
|
||||
defer C.ethash_light_delete(cache)
|
||||
// Generate the actual DAG.
|
||||
d.ptr = C.ethash_full_new_internal(
|
||||
C.CString(d.dir),
|
||||
hashToH256(seedHash),
|
||||
dagSize,
|
||||
cache,
|
||||
(C.ethash_callback_t)(unsafe.Pointer(C.ethashGoCallback_cgo)),
|
||||
)
|
||||
if d.ptr == nil {
|
||||
panic("ethash_full_new IO or memory error")
|
||||
}
|
||||
runtime.SetFinalizer(d, freeDAG)
|
||||
glog.V(logger.Info).Infof("Done generating DAG for epoch %d, it took %v", d.epoch, time.Since(started))
|
||||
})
|
||||
}
|
||||
|
||||
func freeDAG(d *dag) {
|
||||
C.ethash_full_delete(d.ptr)
|
||||
d.ptr = nil
|
||||
}
|
||||
|
||||
func (d *dag) Ptr() unsafe.Pointer {
|
||||
return unsafe.Pointer(d.ptr.data)
|
||||
}
|
||||
|
||||
//export ethashGoCallback
|
||||
func ethashGoCallback(percent C.unsigned) C.int {
|
||||
glog.V(logger.Info).Infof("Generating DAG: %d%%", percent)
|
||||
return 0
|
||||
}
|
||||
|
||||
// MakeDAG pre-generates a DAG file for the given block number in the
|
||||
// given directory. If dir is the empty string, the default directory
|
||||
// is used.
|
||||
func MakeDAG(blockNum uint64, dir string) error {
|
||||
d := &dag{epoch: blockNum / epochLength, dir: dir}
|
||||
if blockNum >= epochLength*2048 {
|
||||
return fmt.Errorf("block number too high, limit is %d", epochLength*2048)
|
||||
}
|
||||
d.generate()
|
||||
if d.ptr == nil {
|
||||
return errors.New("failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Full implements the Search half of the proof of work.
|
||||
type Full struct {
|
||||
Dir string // use this to specify a non-default DAG directory
|
||||
|
||||
test bool // if set use a smaller DAG size
|
||||
turbo bool
|
||||
hashRate int32
|
||||
|
||||
mu sync.Mutex // protects dag
|
||||
current *dag // current full DAG
|
||||
}
|
||||
|
||||
func (pow *Full) getDAG(blockNum uint64) (d *dag) {
|
||||
epoch := blockNum / epochLength
|
||||
pow.mu.Lock()
|
||||
if pow.current != nil && pow.current.epoch == epoch {
|
||||
d = pow.current
|
||||
} else {
|
||||
d = &dag{epoch: epoch, test: pow.test, dir: pow.Dir}
|
||||
pow.current = d
|
||||
}
|
||||
pow.mu.Unlock()
|
||||
// wait for it to finish generating.
|
||||
d.generate()
|
||||
return d
|
||||
}
|
||||
|
||||
func (pow *Full) Search(block pow.Block, stop <-chan struct{}, index int) (nonce uint64, mixDigest []byte) {
|
||||
dag := pow.getDAG(block.NumberU64())
|
||||
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
diff := block.Difficulty()
|
||||
|
||||
i := int64(0)
|
||||
starti := i
|
||||
start := time.Now().UnixNano()
|
||||
previousHashrate := int32(0)
|
||||
|
||||
nonce = uint64(r.Int63())
|
||||
hash := hashToH256(block.HashNoNonce())
|
||||
target := new(big.Int).Div(maxUint256, diff)
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
atomic.AddInt32(&pow.hashRate, -previousHashrate)
|
||||
return 0, nil
|
||||
default:
|
||||
i++
|
||||
|
||||
// we don't have to update hash rate on every nonce, so update after
|
||||
// first nonce check and then after 2^X nonces
|
||||
if i == 2 || ((i % (1 << 16)) == 0) {
|
||||
elapsed := time.Now().UnixNano() - start
|
||||
hashes := (float64(1e9) / float64(elapsed)) * float64(i-starti)
|
||||
hashrateDiff := int32(hashes) - previousHashrate
|
||||
previousHashrate = int32(hashes)
|
||||
atomic.AddInt32(&pow.hashRate, hashrateDiff)
|
||||
}
|
||||
|
||||
ret := C.ethash_full_compute(dag.ptr, hash, C.uint64_t(nonce))
|
||||
result := h256ToHash(ret.result).Big()
|
||||
|
||||
// TODO: disagrees with the spec https://github.com/expanse-org/wiki/wiki/Ethash#mining
|
||||
if ret.success && result.Cmp(target) <= 0 {
|
||||
mixDigest = C.GoBytes(unsafe.Pointer(&ret.mix_hash), C.int(32))
|
||||
atomic.AddInt32(&pow.hashRate, -previousHashrate)
|
||||
return nonce, mixDigest
|
||||
}
|
||||
nonce += 1
|
||||
}
|
||||
|
||||
if !pow.turbo {
|
||||
time.Sleep(20 * time.Microsecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (pow *Full) GetHashrate() int64 {
|
||||
return int64(atomic.LoadInt32(&pow.hashRate))
|
||||
}
|
||||
|
||||
func (pow *Full) Turbo(on bool) {
|
||||
// TODO: this needs to use an atomic operation.
|
||||
pow.turbo = on
|
||||
}
|
||||
|
||||
// Ethash combines block verification with Light and
|
||||
// nonce searching with Full into a single proof of work.
|
||||
type Ethash struct {
|
||||
*Light
|
||||
*Full
|
||||
}
|
||||
|
||||
// New creates an instance of the proof of work.
|
||||
func New() *Ethash {
|
||||
return &Ethash{new(Light), &Full{turbo: true}}
|
||||
}
|
||||
|
||||
// NewShared creates an instance of the proof of work., where a single instance
|
||||
// of the Light cache is shared across all instances created with NewShared.
|
||||
func NewShared() *Ethash {
|
||||
return &Ethash{sharedLight, &Full{turbo: true}}
|
||||
}
|
||||
|
||||
// NewForTesting creates a proof of work for use in unit tests.
|
||||
// It uses a smaller DAG and cache size to keep test times low.
|
||||
// DAG files are stored in a temporary directory.
|
||||
//
|
||||
// Nonces found by a testing instance are not verifiable with a
|
||||
// regular-size cache.
|
||||
func NewForTesting() (*Ethash, error) {
|
||||
dir, err := ioutil.TempDir("", "ethash-test")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Ethash{&Light{test: true}, &Full{Dir: dir, test: true}}, nil
|
||||
}
|
||||
|
||||
func GetSeedHash(blockNum uint64) ([]byte, error) {
|
||||
if blockNum >= epochLength*2048 {
|
||||
return nil, fmt.Errorf("block number too high, limit is %d", epochLength*2048)
|
||||
}
|
||||
sh := makeSeedHash(blockNum / epochLength)
|
||||
return sh[:], nil
|
||||
}
|
||||
|
||||
func makeSeedHash(epoch uint64) (sh common.Hash) {
|
||||
for ; epoch > 0; epoch-- {
|
||||
sh = crypto.Sha3Hash(sh[:])
|
||||
}
|
||||
return sh
|
||||
}
|
||||
221
Godeps/_workspace/src/github.com/expanse-org/ethash/ethash_test.go
generated
vendored
221
Godeps/_workspace/src/github.com/expanse-org/ethash/ethash_test.go
generated
vendored
|
|
@ -1,221 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// Copyright 2015 Lefteris Karapetsas <lefteris@refu.co>
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ethash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// glog.SetV(6)
|
||||
// glog.SetToStderr(true)
|
||||
}
|
||||
|
||||
type testBlock struct {
|
||||
difficulty *big.Int
|
||||
hashNoNonce common.Hash
|
||||
nonce uint64
|
||||
mixDigest common.Hash
|
||||
number uint64
|
||||
}
|
||||
|
||||
func (b *testBlock) Difficulty() *big.Int { return b.difficulty }
|
||||
func (b *testBlock) HashNoNonce() common.Hash { return b.hashNoNonce }
|
||||
func (b *testBlock) Nonce() uint64 { return b.nonce }
|
||||
func (b *testBlock) MixDigest() common.Hash { return b.mixDigest }
|
||||
func (b *testBlock) NumberU64() uint64 { return b.number }
|
||||
|
||||
var validBlocks = []*testBlock{
|
||||
// from proof of concept nine testnet, epoch 0
|
||||
{
|
||||
number: 22,
|
||||
hashNoNonce: common.HexToHash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d"),
|
||||
difficulty: big.NewInt(132416),
|
||||
nonce: 0x495732e0ed7a801c,
|
||||
mixDigest: common.HexToHash("2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5"),
|
||||
},
|
||||
// from proof of concept nine testnet, epoch 1
|
||||
{
|
||||
number: 30001,
|
||||
hashNoNonce: common.HexToHash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34"),
|
||||
difficulty: big.NewInt(1532671),
|
||||
nonce: 0x318df1c8adef7e5e,
|
||||
mixDigest: common.HexToHash("144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84"),
|
||||
},
|
||||
// from proof of concept nine testnet, epoch 2
|
||||
{
|
||||
number: 60000,
|
||||
hashNoNonce: common.HexToHash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0"),
|
||||
difficulty: big.NewInt(2467358),
|
||||
nonce: 0x50377003e5d830ca,
|
||||
mixDigest: common.HexToHash("ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063"),
|
||||
},
|
||||
}
|
||||
|
||||
var invalidZeroDiffBlock = testBlock{
|
||||
number: 61440000,
|
||||
hashNoNonce: crypto.Sha3Hash([]byte("foo")),
|
||||
difficulty: big.NewInt(0),
|
||||
nonce: 0xcafebabec00000fe,
|
||||
mixDigest: crypto.Sha3Hash([]byte("bar")),
|
||||
}
|
||||
|
||||
func TestEthashVerifyValid(t *testing.T) {
|
||||
exp := New()
|
||||
for i, block := range validBlocks {
|
||||
if !exp.Verify(block) {
|
||||
t.Errorf("block %d (%x) did not validate.", i, block.hashNoNonce[:6])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthashVerifyInvalid(t *testing.T) {
|
||||
exp := New()
|
||||
if exp.Verify(&invalidZeroDiffBlock) {
|
||||
t.Errorf("should not validate - we just ensure it does not panic on this block")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthashConcurrentVerify(t *testing.T) {
|
||||
exp, err := NewForTesting()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(exp.Full.Dir)
|
||||
|
||||
block := &testBlock{difficulty: big.NewInt(10)}
|
||||
nonce, md := exp.Search(block, nil, 0)
|
||||
block.nonce = nonce
|
||||
block.mixDigest = common.BytesToHash(md)
|
||||
|
||||
// Verify the block concurrently to check for data races.
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(100)
|
||||
for i := 0; i < 100; i++ {
|
||||
go func() {
|
||||
if !exp.Verify(block) {
|
||||
t.Error("Block could not be verified")
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestEthashConcurrentSearch(t *testing.T) {
|
||||
exp, err := NewForTesting()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exp.Turbo(true)
|
||||
defer os.RemoveAll(exp.Full.Dir)
|
||||
|
||||
type searchRes struct {
|
||||
n uint64
|
||||
md []byte
|
||||
}
|
||||
|
||||
var (
|
||||
block = &testBlock{difficulty: big.NewInt(35000)}
|
||||
nsearch = 10
|
||||
wg = new(sync.WaitGroup)
|
||||
found = make(chan searchRes)
|
||||
stop = make(chan struct{})
|
||||
)
|
||||
rand.Read(block.hashNoNonce[:])
|
||||
wg.Add(nsearch)
|
||||
// launch n searches concurrently.
|
||||
for i := 0; i < nsearch; i++ {
|
||||
go func() {
|
||||
nonce, md := exp.Search(block, stop, 0)
|
||||
select {
|
||||
case found <- searchRes{n: nonce, md: md}:
|
||||
case <-stop:
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// wait for one of them to find the nonce
|
||||
res := <-found
|
||||
// stop the others
|
||||
close(stop)
|
||||
wg.Wait()
|
||||
|
||||
block.nonce = res.n
|
||||
block.mixDigest = common.BytesToHash(res.md)
|
||||
if !exp.Verify(block) {
|
||||
t.Error("Block could not be verified")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthashSearchAcrossEpoch(t *testing.T) {
|
||||
exp, err := NewForTesting()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(exp.Full.Dir)
|
||||
|
||||
for i := epochLength - 40; i < epochLength+40; i++ {
|
||||
block := &testBlock{number: i, difficulty: big.NewInt(90)}
|
||||
rand.Read(block.hashNoNonce[:])
|
||||
nonce, md := exp.Search(block, nil, 0)
|
||||
block.nonce = nonce
|
||||
block.mixDigest = common.BytesToHash(md)
|
||||
if !exp.Verify(block) {
|
||||
t.Fatalf("Block could not be verified")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSeedHash(t *testing.T) {
|
||||
seed0, err := GetSeedHash(0)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get seedHash for block 0: %v", err)
|
||||
}
|
||||
if bytes.Compare(seed0, make([]byte, 32)) != 0 {
|
||||
log.Printf("seedHash for block 0 should be 0s, was: %v\n", seed0)
|
||||
}
|
||||
seed1, err := GetSeedHash(30000)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// From python:
|
||||
// > from pyethash import get_seedhash
|
||||
// > get_seedhash(30000)
|
||||
expectedSeed1, err := hex.DecodeString("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if bytes.Compare(seed1, expectedSeed1) != 0 {
|
||||
log.Printf("seedHash for block 1 should be: %v,\nactual value: %v\n", expectedSeed1, seed1)
|
||||
}
|
||||
|
||||
}
|
||||
51
Godeps/_workspace/src/github.com/expanse-org/ethash/ethashc.go
generated
vendored
51
Godeps/_workspace/src/github.com/expanse-org/ethash/ethashc.go
generated
vendored
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ethash
|
||||
|
||||
/*
|
||||
-mno-stack-arg-probe disables stack probing which avoids the function
|
||||
__chkstk_ms being linked. this avoids a clash of this symbol as we also
|
||||
separately link the secp256k1 lib which ends up defining this symbol
|
||||
|
||||
1. https://gcc.gnu.org/onlinedocs/gccint/Stack-Checking.html
|
||||
2. https://groups.google.com/forum/#!msg/golang-dev/v1bziURSQ4k/88fXuJ24e-gJ
|
||||
3. https://groups.google.com/forum/#!topic/golang-nuts/VNP6Mwz_B6o
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -std=gnu99 -Wall
|
||||
#cgo windows CFLAGS: -mno-stack-arg-probe
|
||||
#cgo LDFLAGS: -lm
|
||||
|
||||
#include "src/libethash/internal.c"
|
||||
#include "src/libethash/sha3.c"
|
||||
#include "src/libethash/io.c"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include "src/libethash/io_win32.c"
|
||||
# include "src/libethash/mmap_win32.c"
|
||||
#else
|
||||
# include "src/libethash/io_posix.c"
|
||||
#endif
|
||||
|
||||
// 'gateway function' for calling back into go.
|
||||
extern int ethashGoCallback(unsigned);
|
||||
int ethashGoCallback_cgo(unsigned percent) { return ethashGoCallback(percent); }
|
||||
|
||||
*/
|
||||
import "C"
|
||||
22
Godeps/_workspace/src/github.com/expanse-org/ethash/js/LICENSE
generated
vendored
22
Godeps/_workspace/src/github.com/expanse-org/ethash/js/LICENSE
generated
vendored
|
|
@ -1,22 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Tim Hughes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
190
Godeps/_workspace/src/github.com/expanse-org/ethash/js/ethash.js
generated
vendored
190
Godeps/_workspace/src/github.com/expanse-org/ethash/js/ethash.js
generated
vendored
|
|
@ -1,190 +0,0 @@
|
|||
// ethash.js
|
||||
// Tim Hughes <tim@twistedfury.com>
|
||||
// Revision 19
|
||||
|
||||
/*jslint node: true, shadow:true */
|
||||
"use strict";
|
||||
|
||||
var Keccak = require('./keccak');
|
||||
var util = require('./util');
|
||||
|
||||
// 32-bit unsigned modulo
|
||||
function mod32(x, n)
|
||||
{
|
||||
return (x>>>0) % (n>>>0);
|
||||
}
|
||||
|
||||
function fnv(x, y)
|
||||
{
|
||||
// js integer multiply by 0x01000193 will lose precision
|
||||
return ((x*0x01000000 | 0) + (x*0x193 | 0)) ^ y;
|
||||
}
|
||||
|
||||
function computeCache(params, seedWords)
|
||||
{
|
||||
var cache = new Uint32Array(params.cacheSize >> 2);
|
||||
var cacheNodeCount = params.cacheSize >> 6;
|
||||
|
||||
// Initialize cache
|
||||
var keccak = new Keccak();
|
||||
keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length);
|
||||
for (var n = 1; n < cacheNodeCount; ++n)
|
||||
{
|
||||
keccak.digestWords(cache, n<<4, 16, cache, (n-1)<<4, 16);
|
||||
}
|
||||
|
||||
var tmp = new Uint32Array(16);
|
||||
|
||||
// Do randmemohash passes
|
||||
for (var r = 0; r < params.cacheRounds; ++r)
|
||||
{
|
||||
for (var n = 0; n < cacheNodeCount; ++n)
|
||||
{
|
||||
var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4;
|
||||
var p1 = mod32(cache[n<<4|0], cacheNodeCount) << 4;
|
||||
|
||||
for (var w = 0; w < 16; w=(w+1)|0)
|
||||
{
|
||||
tmp[w] = cache[p0 | w] ^ cache[p1 | w];
|
||||
}
|
||||
|
||||
keccak.digestWords(cache, n<<4, 16, tmp, 0, tmp.length);
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
function computeDagNode(o_node, params, cache, keccak, nodeIndex)
|
||||
{
|
||||
var cacheNodeCount = params.cacheSize >> 6;
|
||||
var dagParents = params.dagParents;
|
||||
|
||||
var c = (nodeIndex % cacheNodeCount) << 4;
|
||||
var mix = o_node;
|
||||
for (var w = 0; w < 16; ++w)
|
||||
{
|
||||
mix[w] = cache[c|w];
|
||||
}
|
||||
mix[0] ^= nodeIndex;
|
||||
keccak.digestWords(mix, 0, 16, mix, 0, 16);
|
||||
|
||||
for (var p = 0; p < dagParents; ++p)
|
||||
{
|
||||
// compute cache node (word) index
|
||||
c = mod32(fnv(nodeIndex ^ p, mix[p&15]), cacheNodeCount) << 4;
|
||||
|
||||
for (var w = 0; w < 16; ++w)
|
||||
{
|
||||
mix[w] = fnv(mix[w], cache[c|w]);
|
||||
}
|
||||
}
|
||||
|
||||
keccak.digestWords(mix, 0, 16, mix, 0, 16);
|
||||
}
|
||||
|
||||
function computeHashInner(mix, params, cache, keccak, tempNode)
|
||||
{
|
||||
var mixParents = params.mixParents|0;
|
||||
var mixWordCount = params.mixSize >> 2;
|
||||
var mixNodeCount = mixWordCount >> 4;
|
||||
var dagPageCount = (params.dagSize / params.mixSize) >> 0;
|
||||
|
||||
// grab initial first word
|
||||
var s0 = mix[0];
|
||||
|
||||
// initialise mix from initial 64 bytes
|
||||
for (var w = 16; w < mixWordCount; ++w)
|
||||
{
|
||||
mix[w] = mix[w & 15];
|
||||
}
|
||||
|
||||
for (var a = 0; a < mixParents; ++a)
|
||||
{
|
||||
var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount-1)]), dagPageCount);
|
||||
var d = (p * mixNodeCount)|0;
|
||||
|
||||
for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16)
|
||||
{
|
||||
computeDagNode(tempNode, params, cache, keccak, (d + n)|0);
|
||||
|
||||
for (var v = 0; v < 16; ++v)
|
||||
{
|
||||
mix[w|v] = fnv(mix[w|v], tempNode[v]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertSeed(seed)
|
||||
{
|
||||
// todo, reconcile with spec, byte ordering?
|
||||
// todo, big-endian conversion
|
||||
var newSeed = util.toWords(seed);
|
||||
if (newSeed === null)
|
||||
throw Error("Invalid seed '" + seed + "'");
|
||||
return newSeed;
|
||||
}
|
||||
|
||||
exports.defaultParams = function()
|
||||
{
|
||||
return {
|
||||
cacheSize: 1048384,
|
||||
cacheRounds: 3,
|
||||
dagSize: 1073739904,
|
||||
dagParents: 256,
|
||||
mixSize: 128,
|
||||
mixParents: 64,
|
||||
};
|
||||
};
|
||||
|
||||
exports.Ethash = function(params, seed)
|
||||
{
|
||||
// precompute cache and related values
|
||||
seed = convertSeed(seed);
|
||||
var cache = computeCache(params, seed);
|
||||
|
||||
// preallocate buffers/etc
|
||||
var initBuf = new ArrayBuffer(96);
|
||||
var initBytes = new Uint8Array(initBuf);
|
||||
var initWords = new Uint32Array(initBuf);
|
||||
var mixWords = new Uint32Array(params.mixSize / 4);
|
||||
var tempNode = new Uint32Array(16);
|
||||
var keccak = new Keccak();
|
||||
|
||||
var retWords = new Uint32Array(8);
|
||||
var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only
|
||||
|
||||
this.hash = function(header, nonce)
|
||||
{
|
||||
// compute initial hash
|
||||
initBytes.set(header, 0);
|
||||
initBytes.set(nonce, 32);
|
||||
keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length/4);
|
||||
|
||||
// compute mix
|
||||
for (var i = 0; i != 16; ++i)
|
||||
{
|
||||
mixWords[i] = initWords[i];
|
||||
}
|
||||
computeHashInner(mixWords, params, cache, keccak, tempNode);
|
||||
|
||||
// compress mix and append to initWords
|
||||
for (var i = 0; i != mixWords.length; i += 4)
|
||||
{
|
||||
initWords[16 + i/4] = fnv(fnv(fnv(mixWords[i], mixWords[i+1]), mixWords[i+2]), mixWords[i+3]);
|
||||
}
|
||||
|
||||
// final Keccak hashes
|
||||
keccak.digestWords(retWords, 0, 8, initWords, 0, 24); // Keccak-256(s + cmix)
|
||||
return retBytes;
|
||||
};
|
||||
|
||||
this.cacheDigest = function()
|
||||
{
|
||||
return keccak.digest(32, new Uint8Array(cache.buffer));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
404
Godeps/_workspace/src/github.com/expanse-org/ethash/js/keccak.js
generated
vendored
404
Godeps/_workspace/src/github.com/expanse-org/ethash/js/keccak.js
generated
vendored
|
|
@ -1,404 +0,0 @@
|
|||
// keccak.js
|
||||
// Tim Hughes <tim@twistedfury.com>
|
||||
// derived from Markku-Juhani O. Saarinen's C code (http://keccak.noekeon.org/readable_code.html)
|
||||
|
||||
/*jslint node: true, shadow:true */
|
||||
"use strict";
|
||||
|
||||
var Keccak_f1600_RC = new Uint32Array([
|
||||
0x00000001, 0x00000000,
|
||||
0x00008082, 0x00000000,
|
||||
0x0000808a, 0x80000000,
|
||||
0x80008000, 0x80000000,
|
||||
0x0000808b, 0x00000000,
|
||||
0x80000001, 0x00000000,
|
||||
0x80008081, 0x80000000,
|
||||
0x00008009, 0x80000000,
|
||||
0x0000008a, 0x00000000,
|
||||
0x00000088, 0x00000000,
|
||||
0x80008009, 0x00000000,
|
||||
0x8000000a, 0x00000000,
|
||||
0x8000808b, 0x00000000,
|
||||
0x0000008b, 0x80000000,
|
||||
0x00008089, 0x80000000,
|
||||
0x00008003, 0x80000000,
|
||||
0x00008002, 0x80000000,
|
||||
0x00000080, 0x80000000,
|
||||
0x0000800a, 0x00000000,
|
||||
0x8000000a, 0x80000000,
|
||||
0x80008081, 0x80000000,
|
||||
0x00008080, 0x80000000,
|
||||
0x80000001, 0x00000000,
|
||||
0x80008008, 0x80000000
|
||||
]);
|
||||
|
||||
function keccak_f1600(outState, outOffset, outSize, inState)
|
||||
{
|
||||
// todo, handle big endian loads
|
||||
var a00l = inState[0]|0;
|
||||
var a00h = inState[1]|0;
|
||||
var a01l = inState[2]|0;
|
||||
var a01h = inState[3]|0;
|
||||
var a02l = inState[4]|0;
|
||||
var a02h = inState[5]|0;
|
||||
var a03l = inState[6]|0;
|
||||
var a03h = inState[7]|0;
|
||||
var a04l = inState[8]|0;
|
||||
var a04h = inState[9]|0;
|
||||
var a05l = inState[10]|0;
|
||||
var a05h = inState[11]|0;
|
||||
var a06l = inState[12]|0;
|
||||
var a06h = inState[13]|0;
|
||||
var a07l = inState[14]|0;
|
||||
var a07h = inState[15]|0;
|
||||
var a08l = inState[16]|0;
|
||||
var a08h = inState[17]|0;
|
||||
var a09l = inState[18]|0;
|
||||
var a09h = inState[19]|0;
|
||||
var a10l = inState[20]|0;
|
||||
var a10h = inState[21]|0;
|
||||
var a11l = inState[22]|0;
|
||||
var a11h = inState[23]|0;
|
||||
var a12l = inState[24]|0;
|
||||
var a12h = inState[25]|0;
|
||||
var a13l = inState[26]|0;
|
||||
var a13h = inState[27]|0;
|
||||
var a14l = inState[28]|0;
|
||||
var a14h = inState[29]|0;
|
||||
var a15l = inState[30]|0;
|
||||
var a15h = inState[31]|0;
|
||||
var a16l = inState[32]|0;
|
||||
var a16h = inState[33]|0;
|
||||
var a17l = inState[34]|0;
|
||||
var a17h = inState[35]|0;
|
||||
var a18l = inState[36]|0;
|
||||
var a18h = inState[37]|0;
|
||||
var a19l = inState[38]|0;
|
||||
var a19h = inState[39]|0;
|
||||
var a20l = inState[40]|0;
|
||||
var a20h = inState[41]|0;
|
||||
var a21l = inState[42]|0;
|
||||
var a21h = inState[43]|0;
|
||||
var a22l = inState[44]|0;
|
||||
var a22h = inState[45]|0;
|
||||
var a23l = inState[46]|0;
|
||||
var a23h = inState[47]|0;
|
||||
var a24l = inState[48]|0;
|
||||
var a24h = inState[49]|0;
|
||||
var b00l, b00h, b01l, b01h, b02l, b02h, b03l, b03h, b04l, b04h;
|
||||
var b05l, b05h, b06l, b06h, b07l, b07h, b08l, b08h, b09l, b09h;
|
||||
var b10l, b10h, b11l, b11h, b12l, b12h, b13l, b13h, b14l, b14h;
|
||||
var b15l, b15h, b16l, b16h, b17l, b17h, b18l, b18h, b19l, b19h;
|
||||
var b20l, b20h, b21l, b21h, b22l, b22h, b23l, b23h, b24l, b24h;
|
||||
var tl, nl;
|
||||
var th, nh;
|
||||
|
||||
for (var r = 0; r < 48; r = (r+2)|0)
|
||||
{
|
||||
// Theta
|
||||
b00l = a00l ^ a05l ^ a10l ^ a15l ^ a20l;
|
||||
b00h = a00h ^ a05h ^ a10h ^ a15h ^ a20h;
|
||||
b01l = a01l ^ a06l ^ a11l ^ a16l ^ a21l;
|
||||
b01h = a01h ^ a06h ^ a11h ^ a16h ^ a21h;
|
||||
b02l = a02l ^ a07l ^ a12l ^ a17l ^ a22l;
|
||||
b02h = a02h ^ a07h ^ a12h ^ a17h ^ a22h;
|
||||
b03l = a03l ^ a08l ^ a13l ^ a18l ^ a23l;
|
||||
b03h = a03h ^ a08h ^ a13h ^ a18h ^ a23h;
|
||||
b04l = a04l ^ a09l ^ a14l ^ a19l ^ a24l;
|
||||
b04h = a04h ^ a09h ^ a14h ^ a19h ^ a24h;
|
||||
tl = b04l ^ (b01l << 1 | b01h >>> 31);
|
||||
th = b04h ^ (b01h << 1 | b01l >>> 31);
|
||||
a00l ^= tl;
|
||||
a00h ^= th;
|
||||
a05l ^= tl;
|
||||
a05h ^= th;
|
||||
a10l ^= tl;
|
||||
a10h ^= th;
|
||||
a15l ^= tl;
|
||||
a15h ^= th;
|
||||
a20l ^= tl;
|
||||
a20h ^= th;
|
||||
tl = b00l ^ (b02l << 1 | b02h >>> 31);
|
||||
th = b00h ^ (b02h << 1 | b02l >>> 31);
|
||||
a01l ^= tl;
|
||||
a01h ^= th;
|
||||
a06l ^= tl;
|
||||
a06h ^= th;
|
||||
a11l ^= tl;
|
||||
a11h ^= th;
|
||||
a16l ^= tl;
|
||||
a16h ^= th;
|
||||
a21l ^= tl;
|
||||
a21h ^= th;
|
||||
tl = b01l ^ (b03l << 1 | b03h >>> 31);
|
||||
th = b01h ^ (b03h << 1 | b03l >>> 31);
|
||||
a02l ^= tl;
|
||||
a02h ^= th;
|
||||
a07l ^= tl;
|
||||
a07h ^= th;
|
||||
a12l ^= tl;
|
||||
a12h ^= th;
|
||||
a17l ^= tl;
|
||||
a17h ^= th;
|
||||
a22l ^= tl;
|
||||
a22h ^= th;
|
||||
tl = b02l ^ (b04l << 1 | b04h >>> 31);
|
||||
th = b02h ^ (b04h << 1 | b04l >>> 31);
|
||||
a03l ^= tl;
|
||||
a03h ^= th;
|
||||
a08l ^= tl;
|
||||
a08h ^= th;
|
||||
a13l ^= tl;
|
||||
a13h ^= th;
|
||||
a18l ^= tl;
|
||||
a18h ^= th;
|
||||
a23l ^= tl;
|
||||
a23h ^= th;
|
||||
tl = b03l ^ (b00l << 1 | b00h >>> 31);
|
||||
th = b03h ^ (b00h << 1 | b00l >>> 31);
|
||||
a04l ^= tl;
|
||||
a04h ^= th;
|
||||
a09l ^= tl;
|
||||
a09h ^= th;
|
||||
a14l ^= tl;
|
||||
a14h ^= th;
|
||||
a19l ^= tl;
|
||||
a19h ^= th;
|
||||
a24l ^= tl;
|
||||
a24h ^= th;
|
||||
|
||||
// Rho Pi
|
||||
b00l = a00l;
|
||||
b00h = a00h;
|
||||
b10l = a01l << 1 | a01h >>> 31;
|
||||
b10h = a01h << 1 | a01l >>> 31;
|
||||
b07l = a10l << 3 | a10h >>> 29;
|
||||
b07h = a10h << 3 | a10l >>> 29;
|
||||
b11l = a07l << 6 | a07h >>> 26;
|
||||
b11h = a07h << 6 | a07l >>> 26;
|
||||
b17l = a11l << 10 | a11h >>> 22;
|
||||
b17h = a11h << 10 | a11l >>> 22;
|
||||
b18l = a17l << 15 | a17h >>> 17;
|
||||
b18h = a17h << 15 | a17l >>> 17;
|
||||
b03l = a18l << 21 | a18h >>> 11;
|
||||
b03h = a18h << 21 | a18l >>> 11;
|
||||
b05l = a03l << 28 | a03h >>> 4;
|
||||
b05h = a03h << 28 | a03l >>> 4;
|
||||
b16l = a05h << 4 | a05l >>> 28;
|
||||
b16h = a05l << 4 | a05h >>> 28;
|
||||
b08l = a16h << 13 | a16l >>> 19;
|
||||
b08h = a16l << 13 | a16h >>> 19;
|
||||
b21l = a08h << 23 | a08l >>> 9;
|
||||
b21h = a08l << 23 | a08h >>> 9;
|
||||
b24l = a21l << 2 | a21h >>> 30;
|
||||
b24h = a21h << 2 | a21l >>> 30;
|
||||
b04l = a24l << 14 | a24h >>> 18;
|
||||
b04h = a24h << 14 | a24l >>> 18;
|
||||
b15l = a04l << 27 | a04h >>> 5;
|
||||
b15h = a04h << 27 | a04l >>> 5;
|
||||
b23l = a15h << 9 | a15l >>> 23;
|
||||
b23h = a15l << 9 | a15h >>> 23;
|
||||
b19l = a23h << 24 | a23l >>> 8;
|
||||
b19h = a23l << 24 | a23h >>> 8;
|
||||
b13l = a19l << 8 | a19h >>> 24;
|
||||
b13h = a19h << 8 | a19l >>> 24;
|
||||
b12l = a13l << 25 | a13h >>> 7;
|
||||
b12h = a13h << 25 | a13l >>> 7;
|
||||
b02l = a12h << 11 | a12l >>> 21;
|
||||
b02h = a12l << 11 | a12h >>> 21;
|
||||
b20l = a02h << 30 | a02l >>> 2;
|
||||
b20h = a02l << 30 | a02h >>> 2;
|
||||
b14l = a20l << 18 | a20h >>> 14;
|
||||
b14h = a20h << 18 | a20l >>> 14;
|
||||
b22l = a14h << 7 | a14l >>> 25;
|
||||
b22h = a14l << 7 | a14h >>> 25;
|
||||
b09l = a22h << 29 | a22l >>> 3;
|
||||
b09h = a22l << 29 | a22h >>> 3;
|
||||
b06l = a09l << 20 | a09h >>> 12;
|
||||
b06h = a09h << 20 | a09l >>> 12;
|
||||
b01l = a06h << 12 | a06l >>> 20;
|
||||
b01h = a06l << 12 | a06h >>> 20;
|
||||
|
||||
// Chi
|
||||
a00l = b00l ^ ~b01l & b02l;
|
||||
a00h = b00h ^ ~b01h & b02h;
|
||||
a01l = b01l ^ ~b02l & b03l;
|
||||
a01h = b01h ^ ~b02h & b03h;
|
||||
a02l = b02l ^ ~b03l & b04l;
|
||||
a02h = b02h ^ ~b03h & b04h;
|
||||
a03l = b03l ^ ~b04l & b00l;
|
||||
a03h = b03h ^ ~b04h & b00h;
|
||||
a04l = b04l ^ ~b00l & b01l;
|
||||
a04h = b04h ^ ~b00h & b01h;
|
||||
a05l = b05l ^ ~b06l & b07l;
|
||||
a05h = b05h ^ ~b06h & b07h;
|
||||
a06l = b06l ^ ~b07l & b08l;
|
||||
a06h = b06h ^ ~b07h & b08h;
|
||||
a07l = b07l ^ ~b08l & b09l;
|
||||
a07h = b07h ^ ~b08h & b09h;
|
||||
a08l = b08l ^ ~b09l & b05l;
|
||||
a08h = b08h ^ ~b09h & b05h;
|
||||
a09l = b09l ^ ~b05l & b06l;
|
||||
a09h = b09h ^ ~b05h & b06h;
|
||||
a10l = b10l ^ ~b11l & b12l;
|
||||
a10h = b10h ^ ~b11h & b12h;
|
||||
a11l = b11l ^ ~b12l & b13l;
|
||||
a11h = b11h ^ ~b12h & b13h;
|
||||
a12l = b12l ^ ~b13l & b14l;
|
||||
a12h = b12h ^ ~b13h & b14h;
|
||||
a13l = b13l ^ ~b14l & b10l;
|
||||
a13h = b13h ^ ~b14h & b10h;
|
||||
a14l = b14l ^ ~b10l & b11l;
|
||||
a14h = b14h ^ ~b10h & b11h;
|
||||
a15l = b15l ^ ~b16l & b17l;
|
||||
a15h = b15h ^ ~b16h & b17h;
|
||||
a16l = b16l ^ ~b17l & b18l;
|
||||
a16h = b16h ^ ~b17h & b18h;
|
||||
a17l = b17l ^ ~b18l & b19l;
|
||||
a17h = b17h ^ ~b18h & b19h;
|
||||
a18l = b18l ^ ~b19l & b15l;
|
||||
a18h = b18h ^ ~b19h & b15h;
|
||||
a19l = b19l ^ ~b15l & b16l;
|
||||
a19h = b19h ^ ~b15h & b16h;
|
||||
a20l = b20l ^ ~b21l & b22l;
|
||||
a20h = b20h ^ ~b21h & b22h;
|
||||
a21l = b21l ^ ~b22l & b23l;
|
||||
a21h = b21h ^ ~b22h & b23h;
|
||||
a22l = b22l ^ ~b23l & b24l;
|
||||
a22h = b22h ^ ~b23h & b24h;
|
||||
a23l = b23l ^ ~b24l & b20l;
|
||||
a23h = b23h ^ ~b24h & b20h;
|
||||
a24l = b24l ^ ~b20l & b21l;
|
||||
a24h = b24h ^ ~b20h & b21h;
|
||||
|
||||
// Iota
|
||||
a00l ^= Keccak_f1600_RC[r|0];
|
||||
a00h ^= Keccak_f1600_RC[r|1];
|
||||
}
|
||||
|
||||
// todo, handle big-endian stores
|
||||
outState[outOffset|0] = a00l;
|
||||
outState[outOffset|1] = a00h;
|
||||
outState[outOffset|2] = a01l;
|
||||
outState[outOffset|3] = a01h;
|
||||
outState[outOffset|4] = a02l;
|
||||
outState[outOffset|5] = a02h;
|
||||
outState[outOffset|6] = a03l;
|
||||
outState[outOffset|7] = a03h;
|
||||
if (outSize == 8)
|
||||
return;
|
||||
outState[outOffset|8] = a04l;
|
||||
outState[outOffset|9] = a04h;
|
||||
outState[outOffset|10] = a05l;
|
||||
outState[outOffset|11] = a05h;
|
||||
outState[outOffset|12] = a06l;
|
||||
outState[outOffset|13] = a06h;
|
||||
outState[outOffset|14] = a07l;
|
||||
outState[outOffset|15] = a07h;
|
||||
if (outSize == 16)
|
||||
return;
|
||||
outState[outOffset|16] = a08l;
|
||||
outState[outOffset|17] = a08h;
|
||||
outState[outOffset|18] = a09l;
|
||||
outState[outOffset|19] = a09h;
|
||||
outState[outOffset|20] = a10l;
|
||||
outState[outOffset|21] = a10h;
|
||||
outState[outOffset|22] = a11l;
|
||||
outState[outOffset|23] = a11h;
|
||||
outState[outOffset|24] = a12l;
|
||||
outState[outOffset|25] = a12h;
|
||||
outState[outOffset|26] = a13l;
|
||||
outState[outOffset|27] = a13h;
|
||||
outState[outOffset|28] = a14l;
|
||||
outState[outOffset|29] = a14h;
|
||||
outState[outOffset|30] = a15l;
|
||||
outState[outOffset|31] = a15h;
|
||||
outState[outOffset|32] = a16l;
|
||||
outState[outOffset|33] = a16h;
|
||||
outState[outOffset|34] = a17l;
|
||||
outState[outOffset|35] = a17h;
|
||||
outState[outOffset|36] = a18l;
|
||||
outState[outOffset|37] = a18h;
|
||||
outState[outOffset|38] = a19l;
|
||||
outState[outOffset|39] = a19h;
|
||||
outState[outOffset|40] = a20l;
|
||||
outState[outOffset|41] = a20h;
|
||||
outState[outOffset|42] = a21l;
|
||||
outState[outOffset|43] = a21h;
|
||||
outState[outOffset|44] = a22l;
|
||||
outState[outOffset|45] = a22h;
|
||||
outState[outOffset|46] = a23l;
|
||||
outState[outOffset|47] = a23h;
|
||||
outState[outOffset|48] = a24l;
|
||||
outState[outOffset|49] = a24h;
|
||||
}
|
||||
|
||||
var Keccak = function()
|
||||
{
|
||||
var stateBuf = new ArrayBuffer(200);
|
||||
var stateBytes = new Uint8Array(stateBuf);
|
||||
var stateWords = new Uint32Array(stateBuf);
|
||||
|
||||
this.digest = function(oSize, iBytes)
|
||||
{
|
||||
for (var i = 0; i < 50; ++i)
|
||||
{
|
||||
stateWords[i] = 0;
|
||||
}
|
||||
|
||||
var r = 200 - oSize*2;
|
||||
var iLength = iBytes.length;
|
||||
var iOffset = 0;
|
||||
for ( ; ;)
|
||||
{
|
||||
var len = iLength < r ? iLength : r;
|
||||
for (i = 0; i < len; ++i, ++iOffset)
|
||||
{
|
||||
stateBytes[i] ^= iBytes[iOffset];
|
||||
}
|
||||
|
||||
if (iLength < r)
|
||||
break;
|
||||
iLength -= len;
|
||||
|
||||
keccak_f1600(stateWords, 0, 50, stateWords);
|
||||
}
|
||||
|
||||
stateBytes[iLength] ^= 1;
|
||||
stateBytes[r-1] ^= 0x80;
|
||||
keccak_f1600(stateWords, 0, 50, stateWords);
|
||||
return stateBytes.subarray(0, oSize);
|
||||
};
|
||||
|
||||
this.digestWords = function(oWords, oOffset, oLength, iWords, iOffset, iLength)
|
||||
{
|
||||
for (var i = 0; i < 50; ++i)
|
||||
{
|
||||
stateWords[i] = 0;
|
||||
}
|
||||
|
||||
var r = 50 - oLength*2;
|
||||
for (; ; )
|
||||
{
|
||||
var len = iLength < r ? iLength : r;
|
||||
for (i = 0; i < len; ++i, ++iOffset)
|
||||
{
|
||||
stateWords[i] ^= iWords[iOffset];
|
||||
}
|
||||
|
||||
if (iLength < r)
|
||||
break;
|
||||
iLength -= len;
|
||||
|
||||
keccak_f1600(stateWords, 0, 50, stateWords);
|
||||
}
|
||||
|
||||
stateBytes[iLength<<2] ^= 1;
|
||||
stateBytes[(r<<2) - 1] ^= 0x80;
|
||||
keccak_f1600(oWords, oOffset, oLength, stateWords);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Keccak;
|
||||
|
||||
|
||||
201
Godeps/_workspace/src/github.com/expanse-org/ethash/js/makekeccak.js
generated
vendored
201
Godeps/_workspace/src/github.com/expanse-org/ethash/js/makekeccak.js
generated
vendored
|
|
@ -1,201 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
// makekeccak.js
|
||||
// Tim Hughes <tim@twistedfury.com>
|
||||
|
||||
/*jslint node: true, shadow:true */
|
||||
"use strict";
|
||||
|
||||
var Keccak_f1600_Rho = [
|
||||
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
|
||||
];
|
||||
|
||||
var Keccak_f1600_Pi= [
|
||||
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
|
||||
];
|
||||
|
||||
var Keccak_f1600_RC = [
|
||||
0x00000001, 0x00000000,
|
||||
0x00008082, 0x00000000,
|
||||
0x0000808a, 0x80000000,
|
||||
0x80008000, 0x80000000,
|
||||
0x0000808b, 0x00000000,
|
||||
0x80000001, 0x00000000,
|
||||
0x80008081, 0x80000000,
|
||||
0x00008009, 0x80000000,
|
||||
0x0000008a, 0x00000000,
|
||||
0x00000088, 0x00000000,
|
||||
0x80008009, 0x00000000,
|
||||
0x8000000a, 0x00000000,
|
||||
0x8000808b, 0x00000000,
|
||||
0x0000008b, 0x80000000,
|
||||
0x00008089, 0x80000000,
|
||||
0x00008003, 0x80000000,
|
||||
0x00008002, 0x80000000,
|
||||
0x00000080, 0x80000000,
|
||||
0x0000800a, 0x00000000,
|
||||
0x8000000a, 0x80000000,
|
||||
0x80008081, 0x80000000,
|
||||
0x00008080, 0x80000000,
|
||||
0x80000001, 0x00000000,
|
||||
0x80008008, 0x80000000,
|
||||
];
|
||||
|
||||
function makeRotLow(lo, hi, n)
|
||||
{
|
||||
if (n === 0 || n === 32) throw Error("unsupported");
|
||||
if ((n & 0x20) !== 0)
|
||||
{
|
||||
n &= ~0x20;
|
||||
var t = hi;
|
||||
hi = lo;
|
||||
lo = t;
|
||||
}
|
||||
var hir = hi + " >>> " + (32 - n);
|
||||
var los = lo + " << " + n;
|
||||
return los + " | " + hir;
|
||||
}
|
||||
|
||||
function makeRotHigh(lo, hi, n)
|
||||
{
|
||||
if (n === 0 || n === 32) throw Error("unsupported");
|
||||
if ((n & 0x20) !== 0)
|
||||
{
|
||||
n &= ~0x20;
|
||||
var t = hi;
|
||||
hi = lo;
|
||||
lo = t;
|
||||
}
|
||||
var his = hi + " << " + n;
|
||||
var lor = lo + " >>> " + (32 - n);
|
||||
return his + " | " + lor;
|
||||
}
|
||||
|
||||
function makeKeccak_f1600()
|
||||
{
|
||||
var format = function(n)
|
||||
{
|
||||
return n < 10 ? "0"+n : ""+n;
|
||||
};
|
||||
|
||||
var a = function(n, w)
|
||||
{
|
||||
return "a" + format(n) + (w !== 0?'h':'l');
|
||||
};
|
||||
|
||||
var b = function(n, w)
|
||||
{
|
||||
return "b" + format(n) + (w !== 0?'h':'l');
|
||||
};
|
||||
|
||||
var str = "";
|
||||
str += "function keccak_f1600(outState, outOffset, outSize, inState)\n";
|
||||
str += "{\n";
|
||||
|
||||
for (var i = 0; i < 25; ++i)
|
||||
{
|
||||
for (var w = 0; w <= 1; ++w)
|
||||
{
|
||||
str += "\tvar " + a(i,w) + " = inState["+(i<<1|w)+"]|0;\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var j = 0; j < 5; ++j)
|
||||
{
|
||||
str += "\tvar ";
|
||||
for (var i = 0; i < 5; ++i)
|
||||
{
|
||||
if (i !== 0)
|
||||
str += ", ";
|
||||
str += b(j*5+i,0) + ", " + b(j*5+i,1);
|
||||
}
|
||||
str += ";\n";
|
||||
}
|
||||
|
||||
str += "\tvar tl, th;\n";
|
||||
str += "\n";
|
||||
str += "\tfor (var r = 0; r < 48; r = (r+2)|0)\n";
|
||||
str += "\t{\n";
|
||||
|
||||
|
||||
// Theta
|
||||
str += "\t\t// Theta\n";
|
||||
for (var i = 0; i < 5; ++i)
|
||||
{
|
||||
for (var w = 0; w <= 1; ++w)
|
||||
{
|
||||
str += "\t\t" + b(i,w) + " = " + a(i,w) + " ^ " + a(i+5,w) + " ^ " + a(i+10,w) + " ^ " + a(i+15,w) + " ^ " + a(i+20,w) + ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; ++i)
|
||||
{
|
||||
var i4 = (i + 4) % 5;
|
||||
var i1 = (i + 1) % 5;
|
||||
str += "\t\ttl = " + b(i4,0) + " ^ (" + b(i1,0) + " << 1 | " + b(i1,1) + " >>> 31);\n";
|
||||
str += "\t\tth = " + b(i4,1) + " ^ (" + b(i1,1) + " << 1 | " + b(i1,0) + " >>> 31);\n";
|
||||
|
||||
for (var j = 0; j < 25; j = (j+5)|0)
|
||||
{
|
||||
str += "\t\t" + a((j+i),0) + " ^= tl;\n";
|
||||
str += "\t\t" + a((j+i),1) + " ^= th;\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Rho Pi
|
||||
str += "\n\t\t// Rho Pi\n";
|
||||
for (var w = 0; w <= 1; ++w)
|
||||
{
|
||||
str += "\t\t" + b(0,w) + " = " + a(0,w) + ";\n";
|
||||
}
|
||||
var opi = 1;
|
||||
for (var i = 0; i < 24; ++i)
|
||||
{
|
||||
var pi = Keccak_f1600_Pi[i];
|
||||
str += "\t\t" + b(pi,0) + " = " + makeRotLow(a(opi,0), a(opi,1), Keccak_f1600_Rho[i]) + ";\n";
|
||||
str += "\t\t" + b(pi,1) + " = " + makeRotHigh(a(opi,0), a(opi,1), Keccak_f1600_Rho[i]) + ";\n";
|
||||
opi = pi;
|
||||
}
|
||||
|
||||
// Chi
|
||||
str += "\n\t\t// Chi\n";
|
||||
for (var j = 0; j < 25; j += 5)
|
||||
{
|
||||
for (var i = 0; i < 5; ++i)
|
||||
{
|
||||
for (var w = 0; w <= 1; ++w)
|
||||
{
|
||||
str += "\t\t" + a(j+i,w) + " = " + b(j+i,w) + " ^ ~" + b(j+(i+1)%5,w) + " & " + b(j+(i+2)%5,w) + ";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iota
|
||||
str += "\n\t\t// Iota\n";
|
||||
for (var w = 0; w <= 1; ++w)
|
||||
{
|
||||
str += "\t\t" + a(0,w) + " ^= Keccak_f1600_RC[r|" + w + "];\n";
|
||||
}
|
||||
|
||||
|
||||
str += "\t}\n";
|
||||
|
||||
for (var i = 0; i < 25; ++i)
|
||||
{
|
||||
if (i == 4 || i == 8)
|
||||
{
|
||||
str += "\tif (outSize == " + i*2 + ")\n\t\treturn;\n";
|
||||
}
|
||||
for (var w = 0; w <= 1; ++w)
|
||||
{
|
||||
str += "\toutState[outOffset|"+(i<<1|w)+"] = " + a(i,w) + ";\n";
|
||||
}
|
||||
}
|
||||
str += "}\n";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
console.log(makeKeccak_f1600());
|
||||
53
Godeps/_workspace/src/github.com/expanse-org/ethash/js/test.js
generated
vendored
53
Godeps/_workspace/src/github.com/expanse-org/ethash/js/test.js
generated
vendored
|
|
@ -1,53 +0,0 @@
|
|||
// test.js
|
||||
// Tim Hughes <tim@twistedfury.com>
|
||||
|
||||
/*jslint node: true, shadow:true */
|
||||
"use strict";
|
||||
|
||||
var ethash = require('./ethash');
|
||||
var util = require('./util');
|
||||
var Keccak = require('./keccak');
|
||||
|
||||
// sanity check hash functions
|
||||
var src = util.stringToBytes("");
|
||||
if (util.bytesToHexString(new Keccak().digest(32, src)) != "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") throw Error("Keccak-256 failed");
|
||||
if (util.bytesToHexString(new Keccak().digest(64, src)) != "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") throw Error("Keccak-512 failed");
|
||||
|
||||
src = new Uint32Array(src.buffer);
|
||||
var dst = new Uint32Array(8);
|
||||
new Keccak().digestWords(dst, 0, dst.length, src, 0, src.length);
|
||||
if (util.wordsToHexString(dst) != "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") throw Error("Keccak-256 Fast failed");
|
||||
|
||||
var dst = new Uint32Array(16);
|
||||
new Keccak().digestWords(dst, 0, dst.length, src, 0, src.length);
|
||||
if (util.wordsToHexString(dst) != "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") throw Error("Keccak-512 Fast failed");
|
||||
|
||||
|
||||
// init params
|
||||
var ethashParams = ethash.defaultParams();
|
||||
//ethashParams.cacheRounds = 0;
|
||||
|
||||
// create hasher
|
||||
var seed = util.hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466")
|
||||
var startTime = new Date().getTime();
|
||||
var hasher = new ethash.Ethash(ethashParams, seed);
|
||||
console.log('Ethash startup took: '+(new Date().getTime() - startTime) + "ms");
|
||||
console.log('Ethash cache hash: ' + util.bytesToHexString(hasher.cacheDigest()));
|
||||
|
||||
var testHexString = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
|
||||
if (testHexString != util.bytesToHexString(util.hexStringToBytes(testHexString)))
|
||||
throw Error("bytesToHexString or hexStringToBytes broken");
|
||||
|
||||
|
||||
var header = util.hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
|
||||
var nonce = util.hexStringToBytes("0000000000000000");
|
||||
var hash;
|
||||
|
||||
startTime = new Date().getTime();
|
||||
var trials = 10;
|
||||
for (var i = 0; i < trials; ++i)
|
||||
{
|
||||
hash = hasher.hash(header, nonce);
|
||||
}
|
||||
console.log("Light client hashes averaged: " + (new Date().getTime() - startTime)/trials + "ms");
|
||||
console.log("Hash = " + util.bytesToHexString(hash));
|
||||
100
Godeps/_workspace/src/github.com/expanse-org/ethash/js/util.js
generated
vendored
100
Godeps/_workspace/src/github.com/expanse-org/ethash/js/util.js
generated
vendored
|
|
@ -1,100 +0,0 @@
|
|||
// util.js
|
||||
// Tim Hughes <tim@twistedfury.com>
|
||||
|
||||
/*jslint node: true, shadow:true */
|
||||
"use strict";
|
||||
|
||||
function nibbleToChar(nibble)
|
||||
{
|
||||
return String.fromCharCode((nibble < 10 ? 48 : 87) + nibble);
|
||||
}
|
||||
|
||||
function charToNibble(chr)
|
||||
{
|
||||
if (chr >= 48 && chr <= 57)
|
||||
{
|
||||
return chr - 48;
|
||||
}
|
||||
if (chr >= 65 && chr <= 70)
|
||||
{
|
||||
return chr - 65 + 10;
|
||||
}
|
||||
if (chr >= 97 && chr <= 102)
|
||||
{
|
||||
return chr - 97 + 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function stringToBytes(str)
|
||||
{
|
||||
var bytes = new Uint8Array(str.length);
|
||||
for (var i = 0; i != str.length; ++i)
|
||||
{
|
||||
bytes[i] = str.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function hexStringToBytes(str)
|
||||
{
|
||||
var bytes = new Uint8Array(str.length>>>1);
|
||||
for (var i = 0; i != bytes.length; ++i)
|
||||
{
|
||||
bytes[i] = charToNibble(str.charCodeAt(i<<1 | 0)) << 4;
|
||||
bytes[i] |= charToNibble(str.charCodeAt(i<<1 | 1));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function bytesToHexString(bytes)
|
||||
{
|
||||
var str = "";
|
||||
for (var i = 0; i != bytes.length; ++i)
|
||||
{
|
||||
str += nibbleToChar(bytes[i] >>> 4);
|
||||
str += nibbleToChar(bytes[i] & 0xf);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function wordsToHexString(words)
|
||||
{
|
||||
return bytesToHexString(new Uint8Array(words.buffer));
|
||||
}
|
||||
|
||||
function uint32ToHexString(num)
|
||||
{
|
||||
var buf = new Uint8Array(4);
|
||||
buf[0] = (num >> 24) & 0xff;
|
||||
buf[1] = (num >> 16) & 0xff;
|
||||
buf[2] = (num >> 8) & 0xff;
|
||||
buf[3] = (num >> 0) & 0xff;
|
||||
return bytesToHexString(buf);
|
||||
}
|
||||
|
||||
function toWords(input)
|
||||
{
|
||||
if (input instanceof Uint32Array)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
else if (input instanceof Uint8Array)
|
||||
{
|
||||
var tmp = new Uint8Array((input.length + 3) & ~3);
|
||||
tmp.set(input);
|
||||
return new Uint32Array(tmp.buffer);
|
||||
}
|
||||
else if (typeof input === typeof "")
|
||||
{
|
||||
return toWords(stringToBytes(input));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
exports.stringToBytes = stringToBytes;
|
||||
exports.hexStringToBytes = hexStringToBytes;
|
||||
exports.bytesToHexString = bytesToHexString;
|
||||
exports.wordsToHexString = wordsToHexString;
|
||||
exports.uint32ToHexString = uint32ToHexString;
|
||||
exports.toWords = toWords;
|
||||
47
Godeps/_workspace/src/github.com/expanse-org/ethash/setup.py
generated
vendored
47
Godeps/_workspace/src/github.com/expanse-org/ethash/setup.py
generated
vendored
|
|
@ -1,47 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
import os
|
||||
from distutils.core import setup, Extension
|
||||
sources = [
|
||||
'src/python/core.c',
|
||||
'src/libethash/io.c',
|
||||
'src/libethash/internal.c',
|
||||
'src/libethash/sha3.c']
|
||||
if os.name == 'nt':
|
||||
sources += [
|
||||
'src/libethash/util_win32.c',
|
||||
'src/libethash/io_win32.c',
|
||||
'src/libethash/mmap_win32.c',
|
||||
]
|
||||
else:
|
||||
sources += [
|
||||
'src/libethash/io_posix.c'
|
||||
]
|
||||
depends = [
|
||||
'src/libethash/ethash.h',
|
||||
'src/libethash/compiler.h',
|
||||
'src/libethash/data_sizes.h',
|
||||
'src/libethash/endian.h',
|
||||
'src/libethash/ethash.h',
|
||||
'src/libethash/io.h',
|
||||
'src/libethash/fnv.h',
|
||||
'src/libethash/internal.h',
|
||||
'src/libethash/sha3.h',
|
||||
'src/libethash/util.h',
|
||||
]
|
||||
pyethash = Extension('pyethash',
|
||||
sources=sources,
|
||||
depends=depends,
|
||||
extra_compile_args=["-Isrc/", "-std=gnu99", "-Wall"])
|
||||
|
||||
setup(
|
||||
name='pyethash',
|
||||
author="Matthew Wampler-Doty",
|
||||
author_email="matthew.wampler.doty@gmail.com",
|
||||
license='GPL',
|
||||
version='0.1.23',
|
||||
url='https://github.com/expanse-org/ethash',
|
||||
download_url='https://github.com/expanse-org/ethash/tarball/v23',
|
||||
description=('Python wrappers for ethash, the expanse proof of work'
|
||||
'hashing function'),
|
||||
ext_modules=[pyethash],
|
||||
)
|
||||
58
Godeps/_workspace/src/github.com/expanse-org/ethash/src/benchmark/CMakeLists.txt
generated
vendored
58
Godeps/_workspace/src/github.com/expanse-org/ethash/src/benchmark/CMakeLists.txt
generated
vendored
|
|
@ -1,58 +0,0 @@
|
|||
include_directories(..)
|
||||
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
|
||||
if (MSVC)
|
||||
add_definitions("/openmp")
|
||||
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)
|
||||
find_package(MPI)
|
||||
endif()
|
||||
|
||||
if (NOT CRYPTOPP_FOUND)
|
||||
find_package(CryptoPP 5.6.2)
|
||||
endif()
|
||||
|
||||
if (CRYPTOPP_FOUND)
|
||||
add_definitions(-DWITH_CRYPTOPP)
|
||||
find_package (Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
if (NOT OpenCL_FOUND)
|
||||
find_package(OpenCL)
|
||||
endif()
|
||||
if (OpenCL_FOUND)
|
||||
add_definitions(-DWITH_OPENCL)
|
||||
include_directories(${OpenCL_INCLUDE_DIRS})
|
||||
list(APPEND FILES ethash_cl_miner.cpp ethash_cl_miner.h)
|
||||
endif()
|
||||
|
||||
if (MPI_FOUND)
|
||||
include_directories(${MPI_INCLUDE_PATH})
|
||||
add_executable (Benchmark_MPI_FULL benchmark.cpp)
|
||||
target_link_libraries (Benchmark_MPI_FULL ${ETHHASH_LIBS} ${MPI_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
SET_TARGET_PROPERTIES(Benchmark_MPI_FULL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} ${MPI_COMPILE_FLAGS} -DFULL -DMPI")
|
||||
|
||||
add_executable (Benchmark_MPI_LIGHT benchmark.cpp)
|
||||
target_link_libraries (Benchmark_MPI_LIGHT ${ETHHASH_LIBS} ${MPI_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
SET_TARGET_PROPERTIES(Benchmark_MPI_LIGHT PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} ${MPI_COMPILE_FLAGS} -DMPI")
|
||||
endif()
|
||||
|
||||
add_executable (Benchmark_FULL benchmark.cpp)
|
||||
target_link_libraries (Benchmark_FULL ${ETHHASH_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
SET_TARGET_PROPERTIES(Benchmark_FULL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -DFULL")
|
||||
|
||||
add_executable (Benchmark_LIGHT benchmark.cpp)
|
||||
target_link_libraries (Benchmark_LIGHT ${ETHHASH_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if (OpenCL_FOUND)
|
||||
add_executable (Benchmark_CL benchmark.cpp)
|
||||
target_link_libraries (Benchmark_CL ${ETHHASH_LIBS} ethash-cl ${CMAKE_THREAD_LIBS_INIT})
|
||||
SET_TARGET_PROPERTIES(Benchmark_CL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -DOPENCL")
|
||||
endif()
|
||||
278
Godeps/_workspace/src/github.com/expanse-org/ethash/src/benchmark/benchmark.cpp
generated
vendored
278
Godeps/_workspace/src/github.com/expanse-org/ethash/src/benchmark/benchmark.cpp
generated
vendored
|
|
@ -1,278 +0,0 @@
|
|||
/*
|
||||
This file is part of cpp-expanse.
|
||||
|
||||
cpp-expanse is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-expanse is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-expanse. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file benchmark.cpp
|
||||
* @author Tim Hughes <tim@twistedfury.com>
|
||||
* @date 2015
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <chrono>
|
||||
#include <libethash/ethash.h>
|
||||
#include <libethash/util.h>
|
||||
#ifdef OPENCL
|
||||
#include <libethash-cl/ethash_cl_miner.h>
|
||||
#endif
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef WITH_CRYPTOPP
|
||||
#include <libethash/sha3_cryptopp.h>
|
||||
#include <string>
|
||||
|
||||
#else
|
||||
#include "libethash/sha3.h"
|
||||
#endif // WITH_CRYPTOPP
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
using std::chrono::high_resolution_clock;
|
||||
|
||||
#if defined(OPENCL)
|
||||
const unsigned trials = 1024*1024*32;
|
||||
#elif defined(FULL)
|
||||
const unsigned trials = 1024*1024/8;
|
||||
#else
|
||||
const unsigned trials = 1024*1024/1024;
|
||||
#endif
|
||||
uint8_t g_hashes[1024*32];
|
||||
|
||||
static char nibbleToChar(unsigned nibble)
|
||||
{
|
||||
return (char) ((nibble >= 10 ? 'a'-10 : '0') + nibble);
|
||||
}
|
||||
|
||||
static uint8_t charToNibble(char chr)
|
||||
{
|
||||
if (chr >= '0' && chr <= '9')
|
||||
{
|
||||
return (uint8_t) (chr - '0');
|
||||
}
|
||||
if (chr >= 'a' && chr <= 'z')
|
||||
{
|
||||
return (uint8_t) (chr - 'a' + 10);
|
||||
}
|
||||
if (chr >= 'A' && chr <= 'Z')
|
||||
{
|
||||
return (uint8_t) (chr - 'A' + 10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> hexStringToBytes(char const* str)
|
||||
{
|
||||
std::vector<uint8_t> bytes(strlen(str) >> 1);
|
||||
for (unsigned i = 0; i != bytes.size(); ++i)
|
||||
{
|
||||
bytes[i] = charToNibble(str[i*2 | 0]) << 4;
|
||||
bytes[i] |= charToNibble(str[i*2 | 1]);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static std::string bytesToHexString(uint8_t const* bytes, unsigned size)
|
||||
{
|
||||
std::string str;
|
||||
for (unsigned i = 0; i != size; ++i)
|
||||
{
|
||||
str += nibbleToChar(bytes[i] >> 4);
|
||||
str += nibbleToChar(bytes[i] & 0xf);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::string bytesToHexString(ethash_h256_t const *hash, unsigned size)
|
||||
{
|
||||
return bytesToHexString((uint8_t*)hash, size);
|
||||
}
|
||||
|
||||
extern "C" int main(void)
|
||||
{
|
||||
// params for ethash
|
||||
ethash_params params;
|
||||
ethash_params_init(¶ms, 0);
|
||||
//params.full_size = 262147 * 4096; // 1GBish;
|
||||
//params.full_size = 32771 * 4096; // 128MBish;
|
||||
//params.full_size = 8209 * 4096; // 8MBish;
|
||||
//params.cache_size = 8209*4096;
|
||||
//params.cache_size = 2053*4096;
|
||||
ethash_h256_t seed;
|
||||
ethash_h256_t previous_hash;
|
||||
|
||||
memcpy(&seed, hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466").data(), 32);
|
||||
memcpy(&previous_hash, hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").data(), 32);
|
||||
|
||||
// allocate page aligned buffer for dataset
|
||||
#ifdef FULL
|
||||
void* full_mem_buf = malloc(params.full_size + 4095);
|
||||
void* full_mem = (void*)((uintptr_t(full_mem_buf) + 4095) & ~4095);
|
||||
#endif
|
||||
void* cache_mem_buf = malloc(params.cache_size + 63);
|
||||
void* cache_mem = (void*)((uintptr_t(cache_mem_buf) + 63) & ~63);
|
||||
|
||||
ethash_cache cache;
|
||||
cache.mem = cache_mem;
|
||||
|
||||
// compute cache or full data
|
||||
{
|
||||
auto startTime = high_resolution_clock::now();
|
||||
ethash_mkcache(&cache, ¶ms, &seed);
|
||||
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||
|
||||
ethash_h256_t cache_hash;
|
||||
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());
|
||||
|
||||
// print a couple of test hashes
|
||||
{
|
||||
auto startTime = high_resolution_clock::now();
|
||||
ethash_return_value hash;
|
||||
ethash_light(&hash, &cache, ¶ms, &previous_hash, 0);
|
||||
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||
debugf("ethash_light test: %ums, %s\n", (unsigned)time, bytesToHexString(&hash.result, 32).data());
|
||||
}
|
||||
|
||||
#ifdef FULL
|
||||
startTime = high_resolution_clock::now();
|
||||
ethash_compute_full_data(full_mem, ¶ms, &cache);
|
||||
time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||
debugf("ethash_compute_full_data: %ums\n", (unsigned)time);
|
||||
#endif // FULL
|
||||
}
|
||||
|
||||
#ifdef OPENCL
|
||||
ethash_cl_miner miner;
|
||||
{
|
||||
auto startTime = high_resolution_clock::now();
|
||||
if (!miner.init(params, &seed))
|
||||
exit(-1);
|
||||
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||
debugf("ethash_cl_miner init: %ums\n", (unsigned)time);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef FULL
|
||||
{
|
||||
auto startTime = high_resolution_clock::now();
|
||||
ethash_return_value hash;
|
||||
ethash_full(&hash, full_mem, ¶ms, &previous_hash, 0);
|
||||
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();
|
||||
debugf("ethash_full test: %uns\n", (unsigned)time);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OPENCL
|
||||
// validate 1024 hashes against CPU
|
||||
miner.hash(g_hashes, (uint8_t*)&previous_hash, 0, 1024);
|
||||
for (unsigned i = 0; i != 1024; ++i)
|
||||
{
|
||||
ethash_return_value hash;
|
||||
ethash_light(&hash, &cache, ¶ms, &previous_hash, i);
|
||||
if (memcmp(&hash.result, g_hashes + 32*i, 32) != 0)
|
||||
{
|
||||
debugf("nonce %u failed: %s %s\n", i, bytesToHexString(g_hashes + 32*i, 32).c_str(), bytesToHexString(&hash.result, 32).c_str());
|
||||
static unsigned c = 0;
|
||||
if (++c == 16)
|
||||
{
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure nothing else is going on
|
||||
miner.finish();
|
||||
#endif
|
||||
|
||||
auto startTime = high_resolution_clock::now();
|
||||
unsigned hash_count = trials;
|
||||
|
||||
#ifdef OPENCL
|
||||
{
|
||||
struct search_hook : ethash_cl_miner::search_hook
|
||||
{
|
||||
unsigned hash_count;
|
||||
std::vector<uint64_t> nonce_vec;
|
||||
|
||||
virtual bool found(uint64_t const* nonces, uint32_t count)
|
||||
{
|
||||
nonce_vec.insert(nonce_vec.end(), nonces, nonces + count);
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool searched(uint64_t start_nonce, uint32_t count)
|
||||
{
|
||||
// do nothing
|
||||
hash_count += count;
|
||||
return hash_count >= trials;
|
||||
}
|
||||
};
|
||||
search_hook hook;
|
||||
hook.hash_count = 0;
|
||||
|
||||
miner.search((uint8_t*)&previous_hash, 0x000000ffffffffff, hook);
|
||||
|
||||
for (unsigned i = 0; i != hook.nonce_vec.size(); ++i)
|
||||
{
|
||||
uint64_t nonce = hook.nonce_vec[i];
|
||||
ethash_return_value hash;
|
||||
ethash_light(&hash, &cache, ¶ms, &previous_hash, nonce);
|
||||
debugf("found: %.8x%.8x -> %s\n", unsigned(nonce>>32), unsigned(nonce), bytesToHexString(&hash.result, 32).c_str());
|
||||
}
|
||||
|
||||
hash_count = hook.hash_count;
|
||||
}
|
||||
#else
|
||||
{
|
||||
//#pragma omp parallel for
|
||||
for (int nonce = 0; nonce < trials; ++nonce)
|
||||
{
|
||||
ethash_return_value hash;
|
||||
#ifdef FULL
|
||||
ethash_full(&hash, full_mem, ¶ms, &previous_hash, nonce);
|
||||
#else
|
||||
ethash_light(&hash, &cache, ¶ms, &previous_hash, nonce);
|
||||
#endif // FULL
|
||||
}
|
||||
}
|
||||
#endif
|
||||
auto time = std::chrono::duration_cast<std::chrono::microseconds>(high_resolution_clock::now() - startTime).count();
|
||||
debugf("Search took: %ums\n", (unsigned)time/1000);
|
||||
|
||||
unsigned read_size = ETHASH_ACCESSES * ETHASH_MIX_BYTES;
|
||||
#if defined(OPENCL) || defined(FULL)
|
||||
debugf(
|
||||
"hashrate: %8.2f Mh/s, bw: %8.2f GB/s\n",
|
||||
(double)hash_count * (1000*1000)/time / (1000*1000),
|
||||
(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);
|
||||
#ifdef FULL
|
||||
free(full_mem_buf);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
44
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/CMakeLists.txt
generated
vendored
44
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/CMakeLists.txt
generated
vendored
|
|
@ -1,44 +0,0 @@
|
|||
set(LIBRARY ethash)
|
||||
|
||||
if (CPPETHEREUM)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
endif ()
|
||||
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
|
||||
if (NOT MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
|
||||
endif()
|
||||
|
||||
set(FILES util.h
|
||||
io.c
|
||||
internal.c
|
||||
ethash.h
|
||||
endian.h
|
||||
compiler.h
|
||||
fnv.h
|
||||
data_sizes.h)
|
||||
|
||||
if (MSVC)
|
||||
list(APPEND FILES util_win32.c io_win32.c mmap_win32.c)
|
||||
else()
|
||||
list(APPEND FILES io_posix.c)
|
||||
endif()
|
||||
|
||||
if (NOT CRYPTOPP_FOUND)
|
||||
find_package(CryptoPP 5.6.2)
|
||||
endif()
|
||||
|
||||
if (CRYPTOPP_FOUND)
|
||||
add_definitions(-DWITH_CRYPTOPP)
|
||||
include_directories( ${CRYPTOPP_INCLUDE_DIRS} )
|
||||
list(APPEND FILES sha3_cryptopp.cpp sha3_cryptopp.h)
|
||||
else()
|
||||
list(APPEND FILES sha3.c sha3.h)
|
||||
endif()
|
||||
|
||||
add_library(${LIBRARY} ${FILES})
|
||||
|
||||
if (CRYPTOPP_FOUND)
|
||||
TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES})
|
||||
endif()
|
||||
33
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/compiler.h
generated
vendored
33
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/compiler.h
generated
vendored
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
This file is part of cpp-expanse.
|
||||
|
||||
cpp-expanse is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-expanse is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-expanse. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file compiler.h
|
||||
* @date 2014
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// Visual Studio doesn't support the inline keyword in C mode
|
||||
#if defined(_MSC_VER) && !defined(__cplusplus)
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
// pretend restrict is a standard keyword
|
||||
#if defined(_MSC_VER)
|
||||
#define restrict __restrict
|
||||
#else
|
||||
#define restrict __restrict__
|
||||
#endif
|
||||
|
||||
812
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/data_sizes.h
generated
vendored
812
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/data_sizes.h
generated
vendored
|
|
@ -1,812 +0,0 @@
|
|||
/*
|
||||
This file is part of cpp-expanse.
|
||||
|
||||
cpp-expanse 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 FoundationUUU,either version 3 of the LicenseUUU,or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-expanse is distributed in the hope that it will be usefulU,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-expanse. If notUUU,see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file data_sizes.h
|
||||
* @author Matthew Wampler-Doty <negacthulhu@gmail.com>
|
||||
* @date 2015
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// 2048 Epochs (~20 years) worth of tabulated DAG sizes
|
||||
|
||||
// Generated with the following Mathematica Code:
|
||||
|
||||
// GetCacheSizes[n_] := Module[{
|
||||
// CacheSizeBytesInit = 2^24,
|
||||
// CacheGrowth = 2^17,
|
||||
// HashBytes = 64,
|
||||
// j = 0},
|
||||
// Reap[
|
||||
// While[j < n,
|
||||
// Module[{i =
|
||||
// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]},
|
||||
// While[! PrimeQ[i], i--];
|
||||
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
|
||||
|
||||
|
||||
static const uint64_t dag_sizes[2048] = {
|
||||
1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U,
|
||||
1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U,
|
||||
1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U,
|
||||
1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U,
|
||||
1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U,
|
||||
1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U,
|
||||
1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U,
|
||||
1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U,
|
||||
1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U,
|
||||
1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U,
|
||||
1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U,
|
||||
1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U,
|
||||
1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U,
|
||||
1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U,
|
||||
1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U,
|
||||
1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U,
|
||||
1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U,
|
||||
1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U,
|
||||
1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U,
|
||||
1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U,
|
||||
1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U,
|
||||
1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U,
|
||||
1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U,
|
||||
2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U,
|
||||
2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U,
|
||||
2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U,
|
||||
2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U,
|
||||
2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U,
|
||||
2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U,
|
||||
2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U,
|
||||
2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U,
|
||||
2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U,
|
||||
2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U,
|
||||
2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U,
|
||||
2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U,
|
||||
2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U,
|
||||
2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U,
|
||||
2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U,
|
||||
2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U,
|
||||
2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U,
|
||||
2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U,
|
||||
2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U,
|
||||
2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U,
|
||||
2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U,
|
||||
2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U,
|
||||
2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U,
|
||||
3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U,
|
||||
3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U,
|
||||
3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U,
|
||||
3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U,
|
||||
3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U,
|
||||
3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U,
|
||||
3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U,
|
||||
3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U,
|
||||
3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U,
|
||||
3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U,
|
||||
3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U,
|
||||
3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U,
|
||||
3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U,
|
||||
3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U,
|
||||
3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U,
|
||||
3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U,
|
||||
3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U,
|
||||
3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U,
|
||||
3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U,
|
||||
3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U,
|
||||
3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U,
|
||||
3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U,
|
||||
3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U,
|
||||
3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U,
|
||||
4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U,
|
||||
4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U,
|
||||
4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U,
|
||||
4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U,
|
||||
4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U,
|
||||
4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U,
|
||||
4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U,
|
||||
4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U,
|
||||
4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U,
|
||||
4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U,
|
||||
4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U,
|
||||
4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U,
|
||||
4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U,
|
||||
4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U,
|
||||
4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U,
|
||||
4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U,
|
||||
4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U,
|
||||
4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U,
|
||||
4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U,
|
||||
4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U,
|
||||
4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U,
|
||||
4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U,
|
||||
4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U,
|
||||
4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U,
|
||||
5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U,
|
||||
5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U,
|
||||
5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U,
|
||||
5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U,
|
||||
5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U,
|
||||
5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U,
|
||||
5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U,
|
||||
5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U,
|
||||
5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U,
|
||||
5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U,
|
||||
5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U,
|
||||
5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U,
|
||||
5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U,
|
||||
5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U,
|
||||
5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U,
|
||||
5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U,
|
||||
5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U,
|
||||
5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U,
|
||||
5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U,
|
||||
5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U,
|
||||
5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U,
|
||||
5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U,
|
||||
5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U,
|
||||
5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U,
|
||||
6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U,
|
||||
6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U,
|
||||
6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U,
|
||||
6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U,
|
||||
6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U,
|
||||
6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U,
|
||||
6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U,
|
||||
6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U,
|
||||
6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U,
|
||||
6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U,
|
||||
6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U,
|
||||
6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U,
|
||||
6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U,
|
||||
6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U,
|
||||
6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U,
|
||||
6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U,
|
||||
6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U,
|
||||
6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U,
|
||||
6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U,
|
||||
6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U,
|
||||
6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U,
|
||||
6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U,
|
||||
6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U,
|
||||
6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U,
|
||||
7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U,
|
||||
7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U,
|
||||
7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U,
|
||||
7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U,
|
||||
7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U,
|
||||
7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U,
|
||||
7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U,
|
||||
7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U,
|
||||
7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U,
|
||||
7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U,
|
||||
7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U,
|
||||
7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U,
|
||||
7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U,
|
||||
7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U,
|
||||
7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U,
|
||||
7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U,
|
||||
7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U,
|
||||
7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U,
|
||||
7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U,
|
||||
7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U,
|
||||
7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U,
|
||||
7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U,
|
||||
7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U,
|
||||
7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U,
|
||||
8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U,
|
||||
8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U,
|
||||
8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U,
|
||||
8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U,
|
||||
8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U,
|
||||
8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U,
|
||||
8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U,
|
||||
8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U,
|
||||
8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U,
|
||||
8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U,
|
||||
8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U,
|
||||
8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U,
|
||||
8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U,
|
||||
8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U,
|
||||
8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U,
|
||||
8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U,
|
||||
8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U,
|
||||
8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U,
|
||||
8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U,
|
||||
8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U,
|
||||
8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U,
|
||||
8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U,
|
||||
8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U,
|
||||
9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U,
|
||||
9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U,
|
||||
9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U,
|
||||
9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U,
|
||||
9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U,
|
||||
9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U,
|
||||
9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U,
|
||||
9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U,
|
||||
9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U,
|
||||
9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U,
|
||||
9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U,
|
||||
9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U,
|
||||
9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U,
|
||||
9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U,
|
||||
9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U,
|
||||
9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U,
|
||||
9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U,
|
||||
9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U,
|
||||
9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U,
|
||||
9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U,
|
||||
9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U,
|
||||
9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U,
|
||||
9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U,
|
||||
9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U,
|
||||
10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U,
|
||||
10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U,
|
||||
10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U,
|
||||
10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U,
|
||||
10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U,
|
||||
10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U,
|
||||
10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U,
|
||||
10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U,
|
||||
10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U,
|
||||
10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U,
|
||||
10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U,
|
||||
10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U,
|
||||
10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U,
|
||||
10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U,
|
||||
10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U,
|
||||
10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U,
|
||||
10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U,
|
||||
10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U,
|
||||
10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U,
|
||||
10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U,
|
||||
10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U,
|
||||
10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U,
|
||||
10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U,
|
||||
10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U,
|
||||
11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U,
|
||||
11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U,
|
||||
11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U,
|
||||
11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U,
|
||||
11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U,
|
||||
11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U,
|
||||
11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U,
|
||||
11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U,
|
||||
11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U,
|
||||
11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U,
|
||||
11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U,
|
||||
11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U,
|
||||
11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U,
|
||||
11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U,
|
||||
11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U,
|
||||
11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U,
|
||||
11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U,
|
||||
11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U,
|
||||
11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U,
|
||||
11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U,
|
||||
11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U,
|
||||
11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U,
|
||||
11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U,
|
||||
11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U,
|
||||
12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U,
|
||||
12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U,
|
||||
12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U,
|
||||
12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U,
|
||||
12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U,
|
||||
12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U,
|
||||
12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U,
|
||||
12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U,
|
||||
12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U,
|
||||
12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U,
|
||||
12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U,
|
||||
12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U,
|
||||
12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U,
|
||||
12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U,
|
||||
12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U,
|
||||
12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U,
|
||||
12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U,
|
||||
12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U,
|
||||
12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U,
|
||||
12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U,
|
||||
12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U,
|
||||
12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U,
|
||||
12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U,
|
||||
12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U,
|
||||
13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U,
|
||||
13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U,
|
||||
13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U,
|
||||
13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U,
|
||||
13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U,
|
||||
13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U,
|
||||
13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U,
|
||||
13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U,
|
||||
13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U,
|
||||
13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U,
|
||||
13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U,
|
||||
13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U,
|
||||
13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U,
|
||||
13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U,
|
||||
13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U,
|
||||
13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U,
|
||||
13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U,
|
||||
13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U,
|
||||
13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U,
|
||||
13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U,
|
||||
13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U,
|
||||
13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U,
|
||||
13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U,
|
||||
13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U,
|
||||
14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U,
|
||||
14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U,
|
||||
14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U,
|
||||
14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U,
|
||||
14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U,
|
||||
14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U,
|
||||
14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U,
|
||||
14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U,
|
||||
14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U,
|
||||
14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U,
|
||||
14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U,
|
||||
14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U,
|
||||
14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U,
|
||||
14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U,
|
||||
14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U,
|
||||
14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U,
|
||||
14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U,
|
||||
14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U,
|
||||
14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U,
|
||||
14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U,
|
||||
14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U,
|
||||
14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U,
|
||||
14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U,
|
||||
14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U,
|
||||
15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U,
|
||||
15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U,
|
||||
15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U,
|
||||
15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U,
|
||||
15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U,
|
||||
15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U,
|
||||
15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U,
|
||||
15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U,
|
||||
15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U,
|
||||
15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U,
|
||||
15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U,
|
||||
15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U,
|
||||
15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U,
|
||||
15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U,
|
||||
15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U,
|
||||
15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U,
|
||||
15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U,
|
||||
15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U,
|
||||
15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U,
|
||||
15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U,
|
||||
15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U,
|
||||
15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U,
|
||||
15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U,
|
||||
16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U,
|
||||
16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U,
|
||||
16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U,
|
||||
16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U,
|
||||
16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U,
|
||||
16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U,
|
||||
16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U,
|
||||
16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U,
|
||||
16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U,
|
||||
16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U,
|
||||
16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U,
|
||||
16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U,
|
||||
16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U,
|
||||
16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U,
|
||||
16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U,
|
||||
16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U,
|
||||
16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U,
|
||||
16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U,
|
||||
16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U,
|
||||
16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U,
|
||||
16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U,
|
||||
16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U,
|
||||
16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U,
|
||||
16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U,
|
||||
17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U,
|
||||
17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U,
|
||||
17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U,
|
||||
17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U,
|
||||
17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U,
|
||||
17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U,
|
||||
17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U,
|
||||
17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U,
|
||||
17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U,
|
||||
17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U,
|
||||
17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U,
|
||||
17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U,
|
||||
17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U,
|
||||
17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U,
|
||||
17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U,
|
||||
17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U,
|
||||
17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U,
|
||||
17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U,
|
||||
17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U,
|
||||
17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U,
|
||||
17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U,
|
||||
17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U,
|
||||
17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U,
|
||||
17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U,
|
||||
18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U,
|
||||
18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U,
|
||||
18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U,
|
||||
18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U,
|
||||
18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U,
|
||||
18228444544U, 18236833408U, 18245220736U
|
||||
};
|
||||
|
||||
|
||||
// Generated with the following Mathematica Code:
|
||||
|
||||
// GetCacheSizes[n_] := Module[{
|
||||
// DataSetSizeBytesInit = 2^30,
|
||||
// MixBytes = 128,
|
||||
// DataSetGrowth = 2^23,
|
||||
// HashBytes = 64,
|
||||
// CacheMultiplier = 1024,
|
||||
// j = 0},
|
||||
// Reap[
|
||||
// While[j < n,
|
||||
// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]},
|
||||
// While[! PrimeQ[i], i--];
|
||||
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
|
||||
|
||||
const uint64_t cache_sizes[2048] = {
|
||||
16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U,
|
||||
17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U,
|
||||
18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U,
|
||||
19529408U, 19660096U, 19791424U, 19922752U, 20053952U, 20184896U, 20315968U,
|
||||
20446912U, 20576576U, 20709184U, 20840384U, 20971072U, 21102272U, 21233216U,
|
||||
21364544U, 21494848U, 21626816U, 21757376U, 21887552U, 22019392U, 22151104U,
|
||||
22281536U, 22412224U, 22543936U, 22675264U, 22806464U, 22935872U, 23068096U,
|
||||
23198272U, 23330752U, 23459008U, 23592512U, 23723968U, 23854912U, 23986112U,
|
||||
24116672U, 24247616U, 24378688U, 24509504U, 24640832U, 24772544U, 24903488U,
|
||||
25034432U, 25165376U, 25296704U, 25427392U, 25558592U, 25690048U, 25820096U,
|
||||
25951936U, 26081728U, 26214208U, 26345024U, 26476096U, 26606656U, 26737472U,
|
||||
26869184U, 26998208U, 27131584U, 27262528U, 27393728U, 27523904U, 27655744U,
|
||||
27786688U, 27917888U, 28049344U, 28179904U, 28311488U, 28441792U, 28573504U,
|
||||
28700864U, 28835648U, 28966208U, 29096768U, 29228608U, 29359808U, 29490752U,
|
||||
29621824U, 29752256U, 29882816U, 30014912U, 30144448U, 30273728U, 30406976U,
|
||||
30538432U, 30670784U, 30799936U, 30932672U, 31063744U, 31195072U, 31325248U,
|
||||
31456192U, 31588288U, 31719232U, 31850432U, 31981504U, 32110784U, 32243392U,
|
||||
32372672U, 32505664U, 32636608U, 32767808U, 32897344U, 33029824U, 33160768U,
|
||||
33289664U, 33423296U, 33554368U, 33683648U, 33816512U, 33947456U, 34076992U,
|
||||
34208704U, 34340032U, 34471744U, 34600256U, 34734016U, 34864576U, 34993984U,
|
||||
35127104U, 35258176U, 35386688U, 35518528U, 35650624U, 35782336U, 35910976U,
|
||||
36044608U, 36175808U, 36305728U, 36436672U, 36568384U, 36699968U, 36830656U,
|
||||
36961984U, 37093312U, 37223488U, 37355072U, 37486528U, 37617472U, 37747904U,
|
||||
37879232U, 38009792U, 38141888U, 38272448U, 38403392U, 38535104U, 38660672U,
|
||||
38795584U, 38925632U, 39059264U, 39190336U, 39320768U, 39452096U, 39581632U,
|
||||
39713984U, 39844928U, 39974848U, 40107968U, 40238144U, 40367168U, 40500032U,
|
||||
40631744U, 40762816U, 40894144U, 41023552U, 41155904U, 41286208U, 41418304U,
|
||||
41547712U, 41680448U, 41811904U, 41942848U, 42073792U, 42204992U, 42334912U,
|
||||
42467008U, 42597824U, 42729152U, 42860096U, 42991552U, 43122368U, 43253696U,
|
||||
43382848U, 43515712U, 43646912U, 43777088U, 43907648U, 44039104U, 44170432U,
|
||||
44302144U, 44433344U, 44564288U, 44694976U, 44825152U, 44956864U, 45088448U,
|
||||
45219008U, 45350464U, 45481024U, 45612608U, 45744064U, 45874496U, 46006208U,
|
||||
46136768U, 46267712U, 46399424U, 46529344U, 46660672U, 46791488U, 46923328U,
|
||||
47053504U, 47185856U, 47316928U, 47447872U, 47579072U, 47710144U, 47839936U,
|
||||
47971648U, 48103232U, 48234176U, 48365248U, 48496192U, 48627136U, 48757312U,
|
||||
48889664U, 49020736U, 49149248U, 49283008U, 49413824U, 49545152U, 49675712U,
|
||||
49807168U, 49938368U, 50069056U, 50200256U, 50331584U, 50462656U, 50593472U,
|
||||
50724032U, 50853952U, 50986048U, 51117632U, 51248576U, 51379904U, 51510848U,
|
||||
51641792U, 51773248U, 51903296U, 52035136U, 52164032U, 52297664U, 52427968U,
|
||||
52557376U, 52690112U, 52821952U, 52952896U, 53081536U, 53213504U, 53344576U,
|
||||
53475776U, 53608384U, 53738816U, 53870528U, 54000832U, 54131776U, 54263744U,
|
||||
54394688U, 54525248U, 54655936U, 54787904U, 54918592U, 55049152U, 55181248U,
|
||||
55312064U, 55442752U, 55574336U, 55705024U, 55836224U, 55967168U, 56097856U,
|
||||
56228672U, 56358592U, 56490176U, 56621888U, 56753728U, 56884928U, 57015488U,
|
||||
57146816U, 57278272U, 57409216U, 57540416U, 57671104U, 57802432U, 57933632U,
|
||||
58064576U, 58195264U, 58326976U, 58457408U, 58588864U, 58720192U, 58849984U,
|
||||
58981696U, 59113024U, 59243456U, 59375552U, 59506624U, 59637568U, 59768512U,
|
||||
59897792U, 60030016U, 60161984U, 60293056U, 60423872U, 60554432U, 60683968U,
|
||||
60817216U, 60948032U, 61079488U, 61209664U, 61341376U, 61471936U, 61602752U,
|
||||
61733696U, 61865792U, 61996736U, 62127808U, 62259136U, 62389568U, 62520512U,
|
||||
62651584U, 62781632U, 62910784U, 63045056U, 63176128U, 63307072U, 63438656U,
|
||||
63569216U, 63700928U, 63831616U, 63960896U, 64093888U, 64225088U, 64355392U,
|
||||
64486976U, 64617664U, 64748608U, 64879424U, 65009216U, 65142464U, 65273792U,
|
||||
65402816U, 65535424U, 65666752U, 65797696U, 65927744U, 66060224U, 66191296U,
|
||||
66321344U, 66453056U, 66584384U, 66715328U, 66846656U, 66977728U, 67108672U,
|
||||
67239104U, 67370432U, 67501888U, 67631296U, 67763776U, 67895104U, 68026304U,
|
||||
68157248U, 68287936U, 68419264U, 68548288U, 68681408U, 68811968U, 68942912U,
|
||||
69074624U, 69205568U, 69337024U, 69467584U, 69599168U, 69729472U, 69861184U,
|
||||
69989824U, 70122944U, 70253888U, 70385344U, 70515904U, 70647232U, 70778816U,
|
||||
70907968U, 71040832U, 71171648U, 71303104U, 71432512U, 71564992U, 71695168U,
|
||||
71826368U, 71958464U, 72089536U, 72219712U, 72350144U, 72482624U, 72613568U,
|
||||
72744512U, 72875584U, 73006144U, 73138112U, 73268672U, 73400128U, 73530944U,
|
||||
73662272U, 73793344U, 73924544U, 74055104U, 74185792U, 74316992U, 74448832U,
|
||||
74579392U, 74710976U, 74841664U, 74972864U, 75102784U, 75233344U, 75364544U,
|
||||
75497024U, 75627584U, 75759296U, 75890624U, 76021696U, 76152256U, 76283072U,
|
||||
76414144U, 76545856U, 76676672U, 76806976U, 76937792U, 77070016U, 77200832U,
|
||||
77331392U, 77462464U, 77593664U, 77725376U, 77856448U, 77987776U, 78118336U,
|
||||
78249664U, 78380992U, 78511424U, 78642496U, 78773056U, 78905152U, 79033664U,
|
||||
79166656U, 79297472U, 79429568U, 79560512U, 79690816U, 79822784U, 79953472U,
|
||||
80084672U, 80214208U, 80346944U, 80477632U, 80608576U, 80740288U, 80870848U,
|
||||
81002048U, 81133504U, 81264448U, 81395648U, 81525952U, 81657536U, 81786304U,
|
||||
81919808U, 82050112U, 82181312U, 82311616U, 82443968U, 82573376U, 82705984U,
|
||||
82835776U, 82967744U, 83096768U, 83230528U, 83359552U, 83491264U, 83622464U,
|
||||
83753536U, 83886016U, 84015296U, 84147776U, 84277184U, 84409792U, 84540608U,
|
||||
84672064U, 84803008U, 84934336U, 85065152U, 85193792U, 85326784U, 85458496U,
|
||||
85589312U, 85721024U, 85851968U, 85982656U, 86112448U, 86244416U, 86370112U,
|
||||
86506688U, 86637632U, 86769344U, 86900672U, 87031744U, 87162304U, 87293632U,
|
||||
87424576U, 87555392U, 87687104U, 87816896U, 87947968U, 88079168U, 88211264U,
|
||||
88341824U, 88473152U, 88603712U, 88735424U, 88862912U, 88996672U, 89128384U,
|
||||
89259712U, 89390272U, 89521984U, 89652544U, 89783872U, 89914816U, 90045376U,
|
||||
90177088U, 90307904U, 90438848U, 90569152U, 90700096U, 90832832U, 90963776U,
|
||||
91093696U, 91223744U, 91356992U, 91486784U, 91618496U, 91749824U, 91880384U,
|
||||
92012224U, 92143552U, 92273344U, 92405696U, 92536768U, 92666432U, 92798912U,
|
||||
92926016U, 93060544U, 93192128U, 93322816U, 93453632U, 93583936U, 93715136U,
|
||||
93845056U, 93977792U, 94109504U, 94240448U, 94371776U, 94501184U, 94632896U,
|
||||
94764224U, 94895552U, 95023424U, 95158208U, 95287744U, 95420224U, 95550016U,
|
||||
95681216U, 95811904U, 95943872U, 96075328U, 96203584U, 96337856U, 96468544U,
|
||||
96599744U, 96731072U, 96860992U, 96992576U, 97124288U, 97254848U, 97385536U,
|
||||
97517248U, 97647808U, 97779392U, 97910464U, 98041408U, 98172608U, 98303168U,
|
||||
98434496U, 98565568U, 98696768U, 98827328U, 98958784U, 99089728U, 99220928U,
|
||||
99352384U, 99482816U, 99614272U, 99745472U, 99876416U, 100007104U,
|
||||
100138048U, 100267072U, 100401088U, 100529984U, 100662592U, 100791872U,
|
||||
100925248U, 101056064U, 101187392U, 101317952U, 101449408U, 101580608U,
|
||||
101711296U, 101841728U, 101973824U, 102104896U, 102235712U, 102366016U,
|
||||
102498112U, 102628672U, 102760384U, 102890432U, 103021888U, 103153472U,
|
||||
103284032U, 103415744U, 103545152U, 103677248U, 103808576U, 103939648U,
|
||||
104070976U, 104201792U, 104332736U, 104462528U, 104594752U, 104725952U,
|
||||
104854592U, 104988608U, 105118912U, 105247808U, 105381184U, 105511232U,
|
||||
105643072U, 105774784U, 105903296U, 106037056U, 106167872U, 106298944U,
|
||||
106429504U, 106561472U, 106691392U, 106822592U, 106954304U, 107085376U,
|
||||
107216576U, 107346368U, 107478464U, 107609792U, 107739712U, 107872192U,
|
||||
108003136U, 108131392U, 108265408U, 108396224U, 108527168U, 108657344U,
|
||||
108789568U, 108920384U, 109049792U, 109182272U, 109312576U, 109444928U,
|
||||
109572928U, 109706944U, 109837888U, 109969088U, 110099648U, 110230976U,
|
||||
110362432U, 110492992U, 110624704U, 110755264U, 110886208U, 111017408U,
|
||||
111148864U, 111279296U, 111410752U, 111541952U, 111673024U, 111803456U,
|
||||
111933632U, 112066496U, 112196416U, 112328512U, 112457792U, 112590784U,
|
||||
112715968U, 112852672U, 112983616U, 113114944U, 113244224U, 113376448U,
|
||||
113505472U, 113639104U, 113770304U, 113901376U, 114031552U, 114163264U,
|
||||
114294592U, 114425536U, 114556864U, 114687424U, 114818624U, 114948544U,
|
||||
115080512U, 115212224U, 115343296U, 115473472U, 115605184U, 115736128U,
|
||||
115867072U, 115997248U, 116128576U, 116260288U, 116391488U, 116522944U,
|
||||
116652992U, 116784704U, 116915648U, 117046208U, 117178304U, 117308608U,
|
||||
117440192U, 117569728U, 117701824U, 117833024U, 117964096U, 118094656U,
|
||||
118225984U, 118357312U, 118489024U, 118617536U, 118749632U, 118882112U,
|
||||
119012416U, 119144384U, 119275328U, 119406016U, 119537344U, 119668672U,
|
||||
119798464U, 119928896U, 120061376U, 120192832U, 120321728U, 120454336U,
|
||||
120584512U, 120716608U, 120848192U, 120979136U, 121109056U, 121241408U,
|
||||
121372352U, 121502912U, 121634752U, 121764416U, 121895744U, 122027072U,
|
||||
122157632U, 122289088U, 122421184U, 122550592U, 122682944U, 122813888U,
|
||||
122945344U, 123075776U, 123207488U, 123338048U, 123468736U, 123600704U,
|
||||
123731264U, 123861952U, 123993664U, 124124608U, 124256192U, 124386368U,
|
||||
124518208U, 124649024U, 124778048U, 124911296U, 125041088U, 125173696U,
|
||||
125303744U, 125432896U, 125566912U, 125696576U, 125829056U, 125958592U,
|
||||
126090304U, 126221248U, 126352832U, 126483776U, 126615232U, 126746432U,
|
||||
126876608U, 127008704U, 127139392U, 127270336U, 127401152U, 127532224U,
|
||||
127663552U, 127794752U, 127925696U, 128055232U, 128188096U, 128319424U,
|
||||
128449856U, 128581312U, 128712256U, 128843584U, 128973632U, 129103808U,
|
||||
129236288U, 129365696U, 129498944U, 129629888U, 129760832U, 129892288U,
|
||||
130023104U, 130154048U, 130283968U, 130416448U, 130547008U, 130678336U,
|
||||
130807616U, 130939456U, 131071552U, 131202112U, 131331776U, 131464384U,
|
||||
131594048U, 131727296U, 131858368U, 131987392U, 132120256U, 132250816U,
|
||||
132382528U, 132513728U, 132644672U, 132774976U, 132905792U, 133038016U,
|
||||
133168832U, 133299392U, 133429312U, 133562048U, 133692992U, 133823296U,
|
||||
133954624U, 134086336U, 134217152U, 134348608U, 134479808U, 134607296U,
|
||||
134741056U, 134872384U, 135002944U, 135134144U, 135265472U, 135396544U,
|
||||
135527872U, 135659072U, 135787712U, 135921472U, 136052416U, 136182848U,
|
||||
136313792U, 136444864U, 136576448U, 136707904U, 136837952U, 136970048U,
|
||||
137099584U, 137232064U, 137363392U, 137494208U, 137625536U, 137755712U,
|
||||
137887424U, 138018368U, 138149824U, 138280256U, 138411584U, 138539584U,
|
||||
138672832U, 138804928U, 138936128U, 139066688U, 139196864U, 139328704U,
|
||||
139460032U, 139590208U, 139721024U, 139852864U, 139984576U, 140115776U,
|
||||
140245696U, 140376512U, 140508352U, 140640064U, 140769856U, 140902336U,
|
||||
141032768U, 141162688U, 141294016U, 141426496U, 141556544U, 141687488U,
|
||||
141819584U, 141949888U, 142080448U, 142212544U, 142342336U, 142474432U,
|
||||
142606144U, 142736192U, 142868288U, 142997824U, 143129408U, 143258944U,
|
||||
143392448U, 143523136U, 143653696U, 143785024U, 143916992U, 144045632U,
|
||||
144177856U, 144309184U, 144440768U, 144570688U, 144701888U, 144832448U,
|
||||
144965056U, 145096384U, 145227584U, 145358656U, 145489856U, 145620928U,
|
||||
145751488U, 145883072U, 146011456U, 146144704U, 146275264U, 146407232U,
|
||||
146538176U, 146668736U, 146800448U, 146931392U, 147062336U, 147193664U,
|
||||
147324224U, 147455936U, 147586624U, 147717056U, 147848768U, 147979456U,
|
||||
148110784U, 148242368U, 148373312U, 148503232U, 148635584U, 148766144U,
|
||||
148897088U, 149028416U, 149159488U, 149290688U, 149420224U, 149551552U,
|
||||
149683136U, 149814976U, 149943616U, 150076352U, 150208064U, 150338624U,
|
||||
150470464U, 150600256U, 150732224U, 150862784U, 150993088U, 151125952U,
|
||||
151254976U, 151388096U, 151519168U, 151649728U, 151778752U, 151911104U,
|
||||
152042944U, 152174144U, 152304704U, 152435648U, 152567488U, 152698816U,
|
||||
152828992U, 152960576U, 153091648U, 153222976U, 153353792U, 153484096U,
|
||||
153616192U, 153747008U, 153878336U, 154008256U, 154139968U, 154270912U,
|
||||
154402624U, 154533824U, 154663616U, 154795712U, 154926272U, 155057984U,
|
||||
155188928U, 155319872U, 155450816U, 155580608U, 155712064U, 155843392U,
|
||||
155971136U, 156106688U, 156237376U, 156367424U, 156499264U, 156630976U,
|
||||
156761536U, 156892352U, 157024064U, 157155008U, 157284416U, 157415872U,
|
||||
157545536U, 157677248U, 157810496U, 157938112U, 158071744U, 158203328U,
|
||||
158334656U, 158464832U, 158596288U, 158727616U, 158858048U, 158988992U,
|
||||
159121216U, 159252416U, 159381568U, 159513152U, 159645632U, 159776192U,
|
||||
159906496U, 160038464U, 160169536U, 160300352U, 160430656U, 160563008U,
|
||||
160693952U, 160822208U, 160956352U, 161086784U, 161217344U, 161349184U,
|
||||
161480512U, 161611456U, 161742272U, 161873216U, 162002752U, 162135872U,
|
||||
162266432U, 162397888U, 162529216U, 162660032U, 162790976U, 162922048U,
|
||||
163052096U, 163184576U, 163314752U, 163446592U, 163577408U, 163707968U,
|
||||
163839296U, 163969984U, 164100928U, 164233024U, 164364224U, 164494912U,
|
||||
164625856U, 164756672U, 164887616U, 165019072U, 165150016U, 165280064U,
|
||||
165412672U, 165543104U, 165674944U, 165805888U, 165936832U, 166067648U,
|
||||
166198336U, 166330048U, 166461248U, 166591552U, 166722496U, 166854208U,
|
||||
166985408U, 167116736U, 167246656U, 167378368U, 167508416U, 167641024U,
|
||||
167771584U, 167903168U, 168034112U, 168164032U, 168295744U, 168427456U,
|
||||
168557632U, 168688448U, 168819136U, 168951616U, 169082176U, 169213504U,
|
||||
169344832U, 169475648U, 169605952U, 169738048U, 169866304U, 169999552U,
|
||||
170131264U, 170262464U, 170393536U, 170524352U, 170655424U, 170782016U,
|
||||
170917696U, 171048896U, 171179072U, 171310784U, 171439936U, 171573184U,
|
||||
171702976U, 171835072U, 171966272U, 172097216U, 172228288U, 172359232U,
|
||||
172489664U, 172621376U, 172747712U, 172883264U, 173014208U, 173144512U,
|
||||
173275072U, 173407424U, 173539136U, 173669696U, 173800768U, 173931712U,
|
||||
174063424U, 174193472U, 174325696U, 174455744U, 174586816U, 174718912U,
|
||||
174849728U, 174977728U, 175109696U, 175242688U, 175374272U, 175504832U,
|
||||
175636288U, 175765696U, 175898432U, 176028992U, 176159936U, 176291264U,
|
||||
176422592U, 176552512U, 176684864U, 176815424U, 176946496U, 177076544U,
|
||||
177209152U, 177340096U, 177470528U, 177600704U, 177731648U, 177864256U,
|
||||
177994816U, 178126528U, 178257472U, 178387648U, 178518464U, 178650176U,
|
||||
178781888U, 178912064U, 179044288U, 179174848U, 179305024U, 179436736U,
|
||||
179568448U, 179698496U, 179830208U, 179960512U, 180092608U, 180223808U,
|
||||
180354752U, 180485696U, 180617152U, 180748096U, 180877504U, 181009984U,
|
||||
181139264U, 181272512U, 181402688U, 181532608U, 181663168U, 181795136U,
|
||||
181926592U, 182057536U, 182190016U, 182320192U, 182451904U, 182582336U,
|
||||
182713792U, 182843072U, 182976064U, 183107264U, 183237056U, 183368384U,
|
||||
183494848U, 183631424U, 183762752U, 183893824U, 184024768U, 184154816U,
|
||||
184286656U, 184417984U, 184548928U, 184680128U, 184810816U, 184941248U,
|
||||
185072704U, 185203904U, 185335616U, 185465408U, 185596352U, 185727296U,
|
||||
185859904U, 185989696U, 186121664U, 186252992U, 186383552U, 186514112U,
|
||||
186645952U, 186777152U, 186907328U, 187037504U, 187170112U, 187301824U,
|
||||
187429184U, 187562048U, 187693504U, 187825472U, 187957184U, 188087104U,
|
||||
188218304U, 188349376U, 188481344U, 188609728U, 188743616U, 188874304U,
|
||||
189005248U, 189136448U, 189265088U, 189396544U, 189528128U, 189660992U,
|
||||
189791936U, 189923264U, 190054208U, 190182848U, 190315072U, 190447424U,
|
||||
190577984U, 190709312U, 190840768U, 190971328U, 191102656U, 191233472U,
|
||||
191364032U, 191495872U, 191626816U, 191758016U, 191888192U, 192020288U,
|
||||
192148928U, 192282176U, 192413504U, 192542528U, 192674752U, 192805952U,
|
||||
192937792U, 193068608U, 193198912U, 193330496U, 193462208U, 193592384U,
|
||||
193723456U, 193854272U, 193985984U, 194116672U, 194247232U, 194379712U,
|
||||
194508352U, 194641856U, 194772544U, 194900672U, 195035072U, 195166016U,
|
||||
195296704U, 195428032U, 195558592U, 195690304U, 195818176U, 195952576U,
|
||||
196083392U, 196214336U, 196345792U, 196476736U, 196607552U, 196739008U,
|
||||
196869952U, 197000768U, 197130688U, 197262784U, 197394368U, 197523904U,
|
||||
197656384U, 197787584U, 197916608U, 198049472U, 198180544U, 198310208U,
|
||||
198442432U, 198573632U, 198705088U, 198834368U, 198967232U, 199097792U,
|
||||
199228352U, 199360192U, 199491392U, 199621696U, 199751744U, 199883968U,
|
||||
200014016U, 200146624U, 200276672U, 200408128U, 200540096U, 200671168U,
|
||||
200801984U, 200933312U, 201062464U, 201194944U, 201326144U, 201457472U,
|
||||
201588544U, 201719744U, 201850816U, 201981632U, 202111552U, 202244032U,
|
||||
202374464U, 202505152U, 202636352U, 202767808U, 202898368U, 203030336U,
|
||||
203159872U, 203292608U, 203423296U, 203553472U, 203685824U, 203816896U,
|
||||
203947712U, 204078272U, 204208192U, 204341056U, 204472256U, 204603328U,
|
||||
204733888U, 204864448U, 204996544U, 205125568U, 205258304U, 205388864U,
|
||||
205517632U, 205650112U, 205782208U, 205913536U, 206044736U, 206176192U,
|
||||
206307008U, 206434496U, 206569024U, 206700224U, 206831168U, 206961856U,
|
||||
207093056U, 207223616U, 207355328U, 207486784U, 207616832U, 207749056U,
|
||||
207879104U, 208010048U, 208141888U, 208273216U, 208404032U, 208534336U,
|
||||
208666048U, 208796864U, 208927424U, 209059264U, 209189824U, 209321792U,
|
||||
209451584U, 209582656U, 209715136U, 209845568U, 209976896U, 210106432U,
|
||||
210239296U, 210370112U, 210501568U, 210630976U, 210763712U, 210894272U,
|
||||
211024832U, 211156672U, 211287616U, 211418176U, 211549376U, 211679296U,
|
||||
211812032U, 211942592U, 212074432U, 212204864U, 212334016U, 212467648U,
|
||||
212597824U, 212727616U, 212860352U, 212991424U, 213120832U, 213253952U,
|
||||
213385024U, 213515584U, 213645632U, 213777728U, 213909184U, 214040128U,
|
||||
214170688U, 214302656U, 214433728U, 214564544U, 214695232U, 214826048U,
|
||||
214956992U, 215089088U, 215219776U, 215350592U, 215482304U, 215613248U,
|
||||
215743552U, 215874752U, 216005312U, 216137024U, 216267328U, 216399296U,
|
||||
216530752U, 216661696U, 216790592U, 216923968U, 217054528U, 217183168U,
|
||||
217316672U, 217448128U, 217579072U, 217709504U, 217838912U, 217972672U,
|
||||
218102848U, 218233024U, 218364736U, 218496832U, 218627776U, 218759104U,
|
||||
218888896U, 219021248U, 219151936U, 219281728U, 219413056U, 219545024U,
|
||||
219675968U, 219807296U, 219938624U, 220069312U, 220200128U, 220331456U,
|
||||
220461632U, 220592704U, 220725184U, 220855744U, 220987072U, 221117888U,
|
||||
221249216U, 221378368U, 221510336U, 221642048U, 221772736U, 221904832U,
|
||||
222031808U, 222166976U, 222297536U, 222428992U, 222559936U, 222690368U,
|
||||
222820672U, 222953152U, 223083968U, 223213376U, 223345984U, 223476928U,
|
||||
223608512U, 223738688U, 223869376U, 224001472U, 224132672U, 224262848U,
|
||||
224394944U, 224524864U, 224657344U, 224788288U, 224919488U, 225050432U,
|
||||
225181504U, 225312704U, 225443776U, 225574592U, 225704768U, 225834176U,
|
||||
225966784U, 226097216U, 226229824U, 226360384U, 226491712U, 226623424U,
|
||||
226754368U, 226885312U, 227015104U, 227147456U, 227278528U, 227409472U,
|
||||
227539904U, 227669696U, 227802944U, 227932352U, 228065216U, 228196288U,
|
||||
228326464U, 228457792U, 228588736U, 228720064U, 228850112U, 228981056U,
|
||||
229113152U, 229243328U, 229375936U, 229505344U, 229636928U, 229769152U,
|
||||
229894976U, 230030272U, 230162368U, 230292416U, 230424512U, 230553152U,
|
||||
230684864U, 230816704U, 230948416U, 231079616U, 231210944U, 231342016U,
|
||||
231472448U, 231603776U, 231733952U, 231866176U, 231996736U, 232127296U,
|
||||
232259392U, 232388672U, 232521664U, 232652608U, 232782272U, 232914496U,
|
||||
233043904U, 233175616U, 233306816U, 233438528U, 233569984U, 233699776U,
|
||||
233830592U, 233962688U, 234092224U, 234221888U, 234353984U, 234485312U,
|
||||
234618304U, 234749888U, 234880832U, 235011776U, 235142464U, 235274048U,
|
||||
235403456U, 235535936U, 235667392U, 235797568U, 235928768U, 236057152U,
|
||||
236190272U, 236322752U, 236453312U, 236583616U, 236715712U, 236846528U,
|
||||
236976448U, 237108544U, 237239104U, 237371072U, 237501632U, 237630784U,
|
||||
237764416U, 237895232U, 238026688U, 238157632U, 238286912U, 238419392U,
|
||||
238548032U, 238681024U, 238812608U, 238941632U, 239075008U, 239206336U,
|
||||
239335232U, 239466944U, 239599168U, 239730496U, 239861312U, 239992384U,
|
||||
240122816U, 240254656U, 240385856U, 240516928U, 240647872U, 240779072U,
|
||||
240909632U, 241040704U, 241171904U, 241302848U, 241433408U, 241565248U,
|
||||
241696192U, 241825984U, 241958848U, 242088256U, 242220224U, 242352064U,
|
||||
242481856U, 242611648U, 242744896U, 242876224U, 243005632U, 243138496U,
|
||||
243268672U, 243400384U, 243531712U, 243662656U, 243793856U, 243924544U,
|
||||
244054592U, 244187072U, 244316608U, 244448704U, 244580032U, 244710976U,
|
||||
244841536U, 244972864U, 245104448U, 245233984U, 245365312U, 245497792U,
|
||||
245628736U, 245759936U, 245889856U, 246021056U, 246152512U, 246284224U,
|
||||
246415168U, 246545344U, 246675904U, 246808384U, 246939584U, 247070144U,
|
||||
247199552U, 247331648U, 247463872U, 247593536U, 247726016U, 247857088U,
|
||||
247987648U, 248116928U, 248249536U, 248380736U, 248512064U, 248643008U,
|
||||
248773312U, 248901056U, 249036608U, 249167552U, 249298624U, 249429184U,
|
||||
249560512U, 249692096U, 249822784U, 249954112U, 250085312U, 250215488U,
|
||||
250345792U, 250478528U, 250608704U, 250739264U, 250870976U, 251002816U,
|
||||
251133632U, 251263552U, 251395136U, 251523904U, 251657792U, 251789248U,
|
||||
251919424U, 252051392U, 252182464U, 252313408U, 252444224U, 252575552U,
|
||||
252706624U, 252836032U, 252968512U, 253099712U, 253227584U, 253361728U,
|
||||
253493056U, 253623488U, 253754432U, 253885504U, 254017216U, 254148032U,
|
||||
254279488U, 254410432U, 254541376U, 254672576U, 254803264U, 254933824U,
|
||||
255065792U, 255196736U, 255326528U, 255458752U, 255589952U, 255721408U,
|
||||
255851072U, 255983296U, 256114624U, 256244416U, 256374208U, 256507712U,
|
||||
256636096U, 256768832U, 256900544U, 257031616U, 257162176U, 257294272U,
|
||||
257424448U, 257555776U, 257686976U, 257818432U, 257949632U, 258079552U,
|
||||
258211136U, 258342464U, 258473408U, 258603712U, 258734656U, 258867008U,
|
||||
258996544U, 259127744U, 259260224U, 259391296U, 259522112U, 259651904U,
|
||||
259784384U, 259915328U, 260045888U, 260175424U, 260308544U, 260438336U,
|
||||
260570944U, 260700992U, 260832448U, 260963776U, 261092672U, 261226304U,
|
||||
261356864U, 261487936U, 261619648U, 261750592U, 261879872U, 262011968U,
|
||||
262143424U, 262274752U, 262404416U, 262537024U, 262667968U, 262799296U,
|
||||
262928704U, 263061184U, 263191744U, 263322944U, 263454656U, 263585216U,
|
||||
263716672U, 263847872U, 263978944U, 264108608U, 264241088U, 264371648U,
|
||||
264501184U, 264632768U, 264764096U, 264895936U, 265024576U, 265158464U,
|
||||
265287488U, 265418432U, 265550528U, 265681216U, 265813312U, 265943488U,
|
||||
266075968U, 266206144U, 266337728U, 266468032U, 266600384U, 266731072U,
|
||||
266862272U, 266993344U, 267124288U, 267255616U, 267386432U, 267516992U,
|
||||
267648704U, 267777728U, 267910592U, 268040512U, 268172096U, 268302784U,
|
||||
268435264U, 268566208U, 268696256U, 268828096U, 268959296U, 269090368U,
|
||||
269221312U, 269352256U, 269482688U, 269614784U, 269745856U, 269876416U,
|
||||
270007616U, 270139328U, 270270272U, 270401216U, 270531904U, 270663616U,
|
||||
270791744U, 270924736U, 271056832U, 271186112U, 271317184U, 271449536U,
|
||||
271580992U, 271711936U, 271843136U, 271973056U, 272105408U, 272236352U,
|
||||
272367296U, 272498368U, 272629568U, 272759488U, 272891456U, 273022784U,
|
||||
273153856U, 273284672U, 273415616U, 273547072U, 273677632U, 273808448U,
|
||||
273937088U, 274071488U, 274200896U, 274332992U, 274463296U, 274595392U,
|
||||
274726208U, 274857536U, 274988992U, 275118656U, 275250496U, 275382208U,
|
||||
275513024U, 275643968U, 275775296U, 275906368U, 276037184U, 276167872U,
|
||||
276297664U, 276429376U, 276560576U, 276692672U, 276822976U, 276955072U,
|
||||
277085632U, 277216832U, 277347008U, 277478848U, 277609664U, 277740992U,
|
||||
277868608U, 278002624U, 278134336U, 278265536U, 278395328U, 278526784U,
|
||||
278657728U, 278789824U, 278921152U, 279052096U, 279182912U, 279313088U,
|
||||
279443776U, 279576256U, 279706048U, 279838528U, 279969728U, 280099648U,
|
||||
280230976U, 280361408U, 280493632U, 280622528U, 280755392U, 280887104U,
|
||||
281018176U, 281147968U, 281278912U, 281411392U, 281542592U, 281673152U,
|
||||
281803712U, 281935552U, 282066496U, 282197312U, 282329024U, 282458816U,
|
||||
282590272U, 282720832U, 282853184U, 282983744U, 283115072U, 283246144U,
|
||||
283377344U, 283508416U, 283639744U, 283770304U, 283901504U, 284032576U,
|
||||
284163136U, 284294848U, 284426176U, 284556992U, 284687296U, 284819264U,
|
||||
284950208U, 285081536U
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
78
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/endian.h
generated
vendored
78
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/endian.h
generated
vendored
|
|
@ -1,78 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "compiler.h"
|
||||
|
||||
#if defined(__MINGW32__) || defined(_WIN32)
|
||||
# define LITTLE_ENDIAN 1234
|
||||
# define BYTE_ORDER LITTLE_ENDIAN
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||
# include <sys/endian.h>
|
||||
#elif defined(__OpenBSD__) || defined(__SVR4)
|
||||
# include <sys/types.h>
|
||||
#elif defined(__APPLE__)
|
||||
# include <machine/endian.h>
|
||||
#elif defined( BSD ) && (BSD >= 199103)
|
||||
# include <machine/endian.h>
|
||||
#elif defined( __QNXNTO__ ) && defined( __LITTLEENDIAN__ )
|
||||
# define LITTLE_ENDIAN 1234
|
||||
# define BYTE_ORDER LITTLE_ENDIAN
|
||||
#elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ )
|
||||
# define BIG_ENDIAN 1234
|
||||
# define BYTE_ORDER BIG_ENDIAN
|
||||
#else
|
||||
# include <endian.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <stdlib.h>
|
||||
#define ethash_swap_u32(input_) _byteswap_ulong(input_)
|
||||
#define ethash_swap_u64(input_) _byteswap_uint64(input_)
|
||||
#elif defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define ethash_swap_u32(input_) OSSwapInt32(input_)
|
||||
#define ethash_swap_u64(input_) OSSwapInt64(input_)
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||
#define ethash_swap_u32(input_) bswap32(input_)
|
||||
#define ethash_swap_u64(input_) bswap64(input_)
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <endian.h>
|
||||
#define ethash_swap_u32(input_) swap32(input_)
|
||||
#define ethash_swap_u64(input_) swap64(input_)
|
||||
#else // posix
|
||||
#include <byteswap.h>
|
||||
#define ethash_swap_u32(input_) bswap_32(input_)
|
||||
#define ethash_swap_u64(input_) bswap_64(input_)
|
||||
#endif
|
||||
|
||||
|
||||
#if LITTLE_ENDIAN == BYTE_ORDER
|
||||
|
||||
#define fix_endian32(dst_ ,src_) dst_ = src_
|
||||
#define fix_endian32_same(val_)
|
||||
#define fix_endian64(dst_, src_) dst_ = src_
|
||||
#define fix_endian64_same(val_)
|
||||
#define fix_endian_arr32(arr_, size_)
|
||||
#define fix_endian_arr64(arr_, size_)
|
||||
|
||||
#elif BIG_ENDIAN == BYTE_ORDER
|
||||
|
||||
#define fix_endian32(dst_, src_) dst_ = ethash_swap_u32(src_)
|
||||
#define fix_endian32_same(val_) val_ = ethash_swap_u32(val_)
|
||||
#define fix_endian64(dst_, src_) dst_ = ethash_swap_u64(src_)
|
||||
#define fix_endian64_same(val_) val_ = ethash_swap_u64(val_)
|
||||
#define fix_endian_arr32(arr_, size_) \
|
||||
do { \
|
||||
for (unsigned i_ = 0; i_ < (size_); ++i_) { \
|
||||
arr_[i_] = ethash_swap_u32(arr_[i_]); \
|
||||
} \
|
||||
} while (0)
|
||||
#define fix_endian_arr64(arr_, size_) \
|
||||
do { \
|
||||
for (unsigned i_ = 0; i_ < (size_); ++i_) { \
|
||||
arr_[i_] = ethash_swap_u64(arr_[i_]); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# error "endian not supported"
|
||||
#endif // BYTE_ORDER
|
||||
147
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/ethash.h
generated
vendored
147
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/ethash.h
generated
vendored
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
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 ethash.h
|
||||
* @date 2015
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include "compiler.h"
|
||||
|
||||
#define ETHASH_REVISION 23
|
||||
#define ETHASH_DATASET_BYTES_INIT 1073741824U // 2**30
|
||||
#define ETHASH_DATASET_BYTES_GROWTH 8388608U // 2**23
|
||||
#define ETHASH_CACHE_BYTES_INIT 1073741824U // 2**24
|
||||
#define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17
|
||||
#define ETHASH_EPOCH_LENGTH 30000U
|
||||
#define ETHASH_MIX_BYTES 128
|
||||
#define ETHASH_HASH_BYTES 64
|
||||
#define ETHASH_DATASET_PARENTS 256
|
||||
#define ETHASH_CACHE_ROUNDS 3
|
||||
#define ETHASH_ACCESSES 64
|
||||
#define ETHASH_DAG_MAGIC_NUM_SIZE 8
|
||||
#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Type of a seedhash/blockhash e.t.c.
|
||||
typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t;
|
||||
|
||||
// convenience macro to statically initialize an h256_t
|
||||
// usage:
|
||||
// ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... )
|
||||
// have to provide all 32 values. If you don't provide all the rest
|
||||
// will simply be unitialized (not guranteed to be 0)
|
||||
#define ethash_h256_static_init(...) \
|
||||
{ {__VA_ARGS__} }
|
||||
|
||||
struct ethash_light;
|
||||
typedef struct ethash_light* ethash_light_t;
|
||||
struct ethash_full;
|
||||
typedef struct ethash_full* ethash_full_t;
|
||||
typedef int(*ethash_callback_t)(unsigned);
|
||||
|
||||
typedef struct ethash_return_value {
|
||||
ethash_h256_t result;
|
||||
ethash_h256_t mix_hash;
|
||||
bool success;
|
||||
} ethash_return_value_t;
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new ethash_light handler
|
||||
*
|
||||
* @param block_number The block number for which to create the handler
|
||||
* @return Newly allocated ethash_light handler or NULL in case of
|
||||
* ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes()
|
||||
*/
|
||||
ethash_light_t ethash_light_new(uint64_t block_number);
|
||||
/**
|
||||
* Frees a previously allocated ethash_light handler
|
||||
* @param light The light handler to free
|
||||
*/
|
||||
void ethash_light_delete(ethash_light_t light);
|
||||
/**
|
||||
* Calculate the light client data
|
||||
*
|
||||
* @param light The light client handler
|
||||
* @param header_hash The header hash to pack into the mix
|
||||
* @param nonce The nonce to pack into the mix
|
||||
* @return an object of ethash_return_value_t holding the return values
|
||||
*/
|
||||
ethash_return_value_t ethash_light_compute(
|
||||
ethash_light_t light,
|
||||
ethash_h256_t const header_hash,
|
||||
uint64_t nonce
|
||||
);
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new ethash_full handler
|
||||
*
|
||||
* @param light The light handler containing the cache.
|
||||
* @param callback A callback function with signature of @ref ethash_callback_t
|
||||
* It accepts an unsigned with which a progress of DAG calculation
|
||||
* can be displayed. If all goes well the callback should return 0.
|
||||
* If a non-zero value is returned then DAG generation will stop.
|
||||
* Be advised. A progress value of 100 means that DAG creation is
|
||||
* almost complete and that this function will soon return succesfully.
|
||||
* It does not mean that the function has already had a succesfull return.
|
||||
* @return Newly allocated ethash_full handler or NULL in case of
|
||||
* ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
|
||||
*/
|
||||
ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback);
|
||||
|
||||
/**
|
||||
* Frees a previously allocated ethash_full handler
|
||||
* @param full The light handler to free
|
||||
*/
|
||||
void ethash_full_delete(ethash_full_t full);
|
||||
/**
|
||||
* Calculate the full client data
|
||||
*
|
||||
* @param full The full client handler
|
||||
* @param header_hash The header hash to pack into the mix
|
||||
* @param nonce The nonce to pack into the mix
|
||||
* @return An object of ethash_return_value to hold the return value
|
||||
*/
|
||||
ethash_return_value_t ethash_full_compute(
|
||||
ethash_full_t full,
|
||||
ethash_h256_t const header_hash,
|
||||
uint64_t nonce
|
||||
);
|
||||
/**
|
||||
* Get a pointer to the full DAG data
|
||||
*/
|
||||
void const* ethash_full_dag(ethash_full_t full);
|
||||
/**
|
||||
* Get the size of the DAG data
|
||||
*/
|
||||
uint64_t ethash_full_dag_size(ethash_full_t full);
|
||||
|
||||
/**
|
||||
* Calculate the seedhash for a given block number
|
||||
*/
|
||||
ethash_h256_t ethash_get_seedhash(uint64_t block_number);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
43
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/fnv.h
generated
vendored
43
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/fnv.h
generated
vendored
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
This file is part of cpp-expanse.
|
||||
|
||||
cpp-expanse is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-expanse is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-expanse. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file fnv.h
|
||||
* @author Matthew Wampler-Doty <negacthulhu@gmail.com>
|
||||
* @date 2015
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FNV_PRIME 0x01000193
|
||||
|
||||
/* The FNV-1 spec multiplies the prime with the input one byte (octet) in turn.
|
||||
We instead multiply it with the full 32-bit input.
|
||||
This gives a different result compared to a canonical FNV-1 implementation.
|
||||
*/
|
||||
static inline uint32_t fnv_hash(uint32_t const x, uint32_t const y)
|
||||
{
|
||||
return x * FNV_PRIME ^ y;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
507
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/internal.c
generated
vendored
507
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/internal.c
generated
vendored
|
|
@ -1,507 +0,0 @@
|
|||
/*
|
||||
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 cpp-expanse. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file internal.c
|
||||
* @author Tim Hughes <tim@twistedfury.com>
|
||||
* @author Matthew Wampler-Doty
|
||||
* @date 2015
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include "mmap.h"
|
||||
#include "ethash.h"
|
||||
#include "fnv.h"
|
||||
#include "endian.h"
|
||||
#include "internal.h"
|
||||
#include "data_sizes.h"
|
||||
#include "io.h"
|
||||
|
||||
#ifdef WITH_CRYPTOPP
|
||||
|
||||
#include "sha3_cryptopp.h"
|
||||
|
||||
#else
|
||||
#include "sha3.h"
|
||||
#endif // WITH_CRYPTOPP
|
||||
|
||||
uint64_t ethash_get_datasize(uint64_t const block_number)
|
||||
{
|
||||
assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
|
||||
return dag_sizes[block_number / ETHASH_EPOCH_LENGTH];
|
||||
}
|
||||
|
||||
uint64_t ethash_get_cachesize(uint64_t const block_number)
|
||||
{
|
||||
assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
|
||||
return cache_sizes[block_number / ETHASH_EPOCH_LENGTH];
|
||||
}
|
||||
|
||||
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
|
||||
// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
|
||||
// SeqMemoHash(s, R, N)
|
||||
bool static ethash_compute_cache_nodes(
|
||||
node* const nodes,
|
||||
uint64_t cache_size,
|
||||
ethash_h256_t const* seed
|
||||
)
|
||||
{
|
||||
if (cache_size % sizeof(node) != 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node));
|
||||
|
||||
SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32);
|
||||
|
||||
for (uint32_t i = 1; i != num_nodes; ++i) {
|
||||
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) {
|
||||
for (uint32_t i = 0; i != num_nodes; i++) {
|
||||
uint32_t const idx = nodes[i].words[0] % num_nodes;
|
||||
node data;
|
||||
data = nodes[(num_nodes - 1 + i) % num_nodes];
|
||||
for (uint32_t w = 0; w != NODE_WORDS; ++w) {
|
||||
data.words[w] ^= nodes[idx].words[w];
|
||||
}
|
||||
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
|
||||
}
|
||||
}
|
||||
|
||||
// now perform endian conversion
|
||||
fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ethash_calculate_dag_item(
|
||||
node* const ret,
|
||||
uint32_t node_index,
|
||||
ethash_light_t const light
|
||||
)
|
||||
{
|
||||
uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node));
|
||||
node const* cache_nodes = (node const *) light->cache;
|
||||
node const* init = &cache_nodes[node_index % num_parent_nodes];
|
||||
memcpy(ret, init, sizeof(node));
|
||||
ret->words[0] ^= node_index;
|
||||
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
|
||||
#if defined(_M_X64) && ENABLE_SSE
|
||||
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
|
||||
__m128i xmm0 = ret->xmm[0];
|
||||
__m128i xmm1 = ret->xmm[1];
|
||||
__m128i xmm2 = ret->xmm[2];
|
||||
__m128i xmm3 = ret->xmm[3];
|
||||
#endif
|
||||
|
||||
for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
|
||||
uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes;
|
||||
node const *parent = &cache_nodes[parent_index];
|
||||
|
||||
#if defined(_M_X64) && ENABLE_SSE
|
||||
{
|
||||
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
|
||||
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
|
||||
xmm2 = _mm_mullo_epi32(xmm2, fnv_prime);
|
||||
xmm3 = _mm_mullo_epi32(xmm3, fnv_prime);
|
||||
xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]);
|
||||
xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]);
|
||||
xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]);
|
||||
xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]);
|
||||
|
||||
// have to write to ret as values are used to compute index
|
||||
ret->xmm[0] = xmm0;
|
||||
ret->xmm[1] = xmm1;
|
||||
ret->xmm[2] = xmm2;
|
||||
ret->xmm[3] = xmm3;
|
||||
}
|
||||
#else
|
||||
{
|
||||
for (unsigned w = 0; w != NODE_WORDS; ++w) {
|
||||
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
|
||||
}
|
||||
|
||||
bool ethash_compute_full_data(
|
||||
void* mem,
|
||||
uint64_t full_size,
|
||||
ethash_light_t const light,
|
||||
ethash_callback_t callback
|
||||
)
|
||||
{
|
||||
if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 ||
|
||||
(full_size % sizeof(node)) != 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t const max_n = (uint32_t)(full_size / sizeof(node));
|
||||
node* full_nodes = mem;
|
||||
double const progress_change = 1.0f / max_n;
|
||||
double progress = 0.0f;
|
||||
// now compute full nodes
|
||||
for (uint32_t n = 0; n != max_n; ++n) {
|
||||
if (callback &&
|
||||
n % (max_n / 100) == 0 &&
|
||||
callback((unsigned int)(ceil(progress * 100.0f))) != 0) {
|
||||
|
||||
return false;
|
||||
}
|
||||
progress += progress_change;
|
||||
ethash_calculate_dag_item(&(full_nodes[n]), n, light);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ethash_hash(
|
||||
ethash_return_value_t* ret,
|
||||
node const* full_nodes,
|
||||
ethash_light_t const light,
|
||||
uint64_t full_size,
|
||||
ethash_h256_t const header_hash,
|
||||
uint64_t const nonce
|
||||
)
|
||||
{
|
||||
if (full_size % MIX_WORDS != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// pack hash and nonce togexper into first 40 bytes of s_mix
|
||||
assert(sizeof(node) * 8 == 512);
|
||||
node s_mix[MIX_NODES + 1];
|
||||
memcpy(s_mix[0].bytes, &header_hash, 32);
|
||||
fix_endian64(s_mix[0].double_words[4], nonce);
|
||||
|
||||
// compute sha3-512 hash and replicate across mix
|
||||
SHA3_512(s_mix->bytes, s_mix->bytes, 40);
|
||||
fix_endian_arr32(s_mix[0].words, 16);
|
||||
|
||||
node* const mix = s_mix + 1;
|
||||
for (uint32_t w = 0; w != MIX_WORDS; ++w) {
|
||||
mix->words[w] = s_mix[0].words[w % NODE_WORDS];
|
||||
}
|
||||
|
||||
unsigned const page_size = sizeof(uint32_t) * MIX_WORDS;
|
||||
unsigned const num_full_pages = (unsigned) (full_size / page_size);
|
||||
|
||||
for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) {
|
||||
uint32_t const index = fnv_hash(s_mix->words[0] ^ i, mix->words[i % MIX_WORDS]) % num_full_pages;
|
||||
|
||||
for (unsigned n = 0; n != MIX_NODES; ++n) {
|
||||
node const* dag_node;
|
||||
if (full_nodes) {
|
||||
dag_node = &full_nodes[MIX_NODES * index + n];
|
||||
} else {
|
||||
node tmp_node;
|
||||
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light);
|
||||
dag_node = &tmp_node;
|
||||
}
|
||||
|
||||
#if defined(_M_X64) && ENABLE_SSE
|
||||
{
|
||||
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
|
||||
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
|
||||
__m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]);
|
||||
__m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]);
|
||||
__m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]);
|
||||
mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]);
|
||||
mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]);
|
||||
mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
|
||||
mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
|
||||
}
|
||||
#else
|
||||
{
|
||||
for (unsigned w = 0; w != NODE_WORDS; ++w) {
|
||||
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// compress mix
|
||||
for (uint32_t w = 0; w != MIX_WORDS; w += 4) {
|
||||
uint32_t reduction = mix->words[w + 0];
|
||||
reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
|
||||
reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
|
||||
reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
|
||||
mix->words[w / 4] = reduction;
|
||||
}
|
||||
|
||||
fix_endian_arr32(mix->words, MIX_WORDS / 4);
|
||||
memcpy(&ret->mix_hash, mix->bytes, 32);
|
||||
// final Keccak hash
|
||||
SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ethash_quick_hash(
|
||||
ethash_h256_t* return_hash,
|
||||
ethash_h256_t const* header_hash,
|
||||
uint64_t nonce,
|
||||
ethash_h256_t const* mix_hash
|
||||
)
|
||||
{
|
||||
uint8_t buf[64 + 32];
|
||||
memcpy(buf, header_hash, 32);
|
||||
fix_endian64_same(nonce);
|
||||
memcpy(&(buf[32]), &nonce, 8);
|
||||
SHA3_512(buf, buf, 40);
|
||||
memcpy(&(buf[64]), mix_hash, 32);
|
||||
SHA3_256(return_hash, buf, 64 + 32);
|
||||
}
|
||||
|
||||
ethash_h256_t ethash_get_seedhash(uint64_t block_number)
|
||||
{
|
||||
ethash_h256_t ret;
|
||||
ethash_h256_reset(&ret);
|
||||
uint64_t const epochs = block_number / ETHASH_EPOCH_LENGTH;
|
||||
for (uint32_t i = 0; i < epochs; ++i)
|
||||
SHA3_256(&ret, (uint8_t*)&ret, 32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ethash_quick_check_difficulty(
|
||||
ethash_h256_t const* header_hash,
|
||||
uint64_t const nonce,
|
||||
ethash_h256_t const* mix_hash,
|
||||
ethash_h256_t const* boundary
|
||||
)
|
||||
{
|
||||
|
||||
ethash_h256_t return_hash;
|
||||
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
|
||||
return ethash_check_difficulty(&return_hash, boundary);
|
||||
}
|
||||
|
||||
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
|
||||
{
|
||||
struct ethash_light *ret;
|
||||
ret = calloc(sizeof(*ret), 1);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
ret->cache = malloc((size_t)cache_size);
|
||||
if (!ret->cache) {
|
||||
goto fail_free_light;
|
||||
}
|
||||
node* nodes = (node*)ret->cache;
|
||||
if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) {
|
||||
goto fail_free_cache_mem;
|
||||
}
|
||||
ret->cache_size = cache_size;
|
||||
return ret;
|
||||
|
||||
fail_free_cache_mem:
|
||||
free(ret->cache);
|
||||
fail_free_light:
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ethash_light_t ethash_light_new(uint64_t block_number)
|
||||
{
|
||||
ethash_h256_t seedhash = ethash_get_seedhash(block_number);
|
||||
ethash_light_t ret;
|
||||
ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash);
|
||||
ret->block_number = block_number;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ethash_light_delete(ethash_light_t light)
|
||||
{
|
||||
if (light->cache) {
|
||||
free(light->cache);
|
||||
}
|
||||
free(light);
|
||||
}
|
||||
|
||||
ethash_return_value_t ethash_light_compute_internal(
|
||||
ethash_light_t light,
|
||||
uint64_t full_size,
|
||||
ethash_h256_t const header_hash,
|
||||
uint64_t nonce
|
||||
)
|
||||
{
|
||||
ethash_return_value_t ret;
|
||||
ret.success = true;
|
||||
if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) {
|
||||
ret.success = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ethash_return_value_t ethash_light_compute(
|
||||
ethash_light_t light,
|
||||
ethash_h256_t const header_hash,
|
||||
uint64_t nonce
|
||||
)
|
||||
{
|
||||
uint64_t full_size = ethash_get_datasize(light->block_number);
|
||||
return ethash_light_compute_internal(light, full_size, header_hash, nonce);
|
||||
}
|
||||
|
||||
static bool ethash_mmap(struct ethash_full* ret, FILE* f)
|
||||
{
|
||||
int fd;
|
||||
char* mmapped_data;
|
||||
errno = 0;
|
||||
ret->file = f;
|
||||
if ((fd = ethash_fileno(ret->file)) == -1) {
|
||||
return false;
|
||||
}
|
||||
mmapped_data= mmap(
|
||||
NULL,
|
||||
(size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
fd,
|
||||
0
|
||||
);
|
||||
if (mmapped_data == MAP_FAILED) {
|
||||
return false;
|
||||
}
|
||||
ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
ethash_full_t ethash_full_new_internal(
|
||||
char const* dirname,
|
||||
ethash_h256_t const seed_hash,
|
||||
uint64_t full_size,
|
||||
ethash_light_t const light,
|
||||
ethash_callback_t callback
|
||||
)
|
||||
{
|
||||
struct ethash_full* ret;
|
||||
FILE *f = NULL;
|
||||
ret = calloc(sizeof(*ret), 1);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
ret->file_size = (size_t)full_size;
|
||||
switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
|
||||
case ETHASH_IO_FAIL:
|
||||
// ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case
|
||||
goto fail_free_full;
|
||||
case ETHASH_IO_MEMO_MATCH:
|
||||
if (!ethash_mmap(ret, f)) {
|
||||
ETHASH_CRITICAL("mmap failure()");
|
||||
goto fail_close_file;
|
||||
}
|
||||
return ret;
|
||||
case ETHASH_IO_MEMO_SIZE_MISMATCH:
|
||||
// if a DAG of same filename but unexpected size is found, silently force new file creation
|
||||
if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
|
||||
ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size.");
|
||||
goto fail_free_full;
|
||||
}
|
||||
// fallthrough to the mismatch case here, DO NOT go through match
|
||||
case ETHASH_IO_MEMO_MISMATCH:
|
||||
if (!ethash_mmap(ret, f)) {
|
||||
ETHASH_CRITICAL("mmap failure()");
|
||||
goto fail_close_file;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
|
||||
ETHASH_CRITICAL("Failure at computing DAG data.");
|
||||
goto fail_free_full_data;
|
||||
}
|
||||
|
||||
// after the DAG has been filled then we finalize it by writting the magic number at the beginning
|
||||
if (fseek(f, 0, SEEK_SET) != 0) {
|
||||
ETHASH_CRITICAL("Could not seek to DAG file start to write magic number.");
|
||||
goto fail_free_full_data;
|
||||
}
|
||||
uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM;
|
||||
if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
|
||||
ETHASH_CRITICAL("Could not write magic number to DAG's beginning.");
|
||||
goto fail_free_full_data;
|
||||
}
|
||||
if (fflush(f) != 0) {// make sure the magic number IS there
|
||||
ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?");
|
||||
goto fail_free_full_data;
|
||||
}
|
||||
return ret;
|
||||
|
||||
fail_free_full_data:
|
||||
// could check that munmap(..) == 0 but even if it did not can't really do anything here
|
||||
munmap(ret->data, (size_t)full_size);
|
||||
fail_close_file:
|
||||
fclose(ret->file);
|
||||
fail_free_full:
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback)
|
||||
{
|
||||
char strbuf[256];
|
||||
if (!ethash_get_default_dirname(strbuf, 256)) {
|
||||
return NULL;
|
||||
}
|
||||
uint64_t full_size = ethash_get_datasize(light->block_number);
|
||||
ethash_h256_t seedhash = ethash_get_seedhash(light->block_number);
|
||||
return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback);
|
||||
}
|
||||
|
||||
void ethash_full_delete(ethash_full_t full)
|
||||
{
|
||||
// could check that munmap(..) == 0 but even if it did not can't really do anything here
|
||||
munmap(full->data, (size_t)full->file_size);
|
||||
if (full->file) {
|
||||
fclose(full->file);
|
||||
}
|
||||
free(full);
|
||||
}
|
||||
|
||||
ethash_return_value_t ethash_full_compute(
|
||||
ethash_full_t full,
|
||||
ethash_h256_t const header_hash,
|
||||
uint64_t nonce
|
||||
)
|
||||
{
|
||||
ethash_return_value_t ret;
|
||||
ret.success = true;
|
||||
if (!ethash_hash(
|
||||
&ret,
|
||||
(node const*)full->data,
|
||||
NULL,
|
||||
full->file_size,
|
||||
header_hash,
|
||||
nonce)) {
|
||||
ret.success = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void const* ethash_full_dag(ethash_full_t full)
|
||||
{
|
||||
return full->data;
|
||||
}
|
||||
|
||||
uint64_t ethash_full_dag_size(ethash_full_t full)
|
||||
{
|
||||
return full->file_size;
|
||||
}
|
||||
179
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/internal.h
generated
vendored
179
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/internal.h
generated
vendored
|
|
@ -1,179 +0,0 @@
|
|||
#pragma once
|
||||
#include "compiler.h"
|
||||
#include "endian.h"
|
||||
#include "ethash.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define ENABLE_SSE 0
|
||||
|
||||
#if defined(_M_X64) && ENABLE_SSE
|
||||
#include <smmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// compile time settings
|
||||
#define NODE_WORDS (64/4)
|
||||
#define MIX_WORDS (ETHASH_MIX_BYTES/4)
|
||||
#define MIX_NODES (MIX_WORDS / NODE_WORDS)
|
||||
#include <stdint.h>
|
||||
|
||||
typedef union node {
|
||||
uint8_t bytes[NODE_WORDS * 4];
|
||||
uint32_t words[NODE_WORDS];
|
||||
uint64_t double_words[NODE_WORDS / 2];
|
||||
|
||||
#if defined(_M_X64) && ENABLE_SSE
|
||||
__m128i xmm[NODE_WORDS/4];
|
||||
#endif
|
||||
|
||||
} node;
|
||||
|
||||
static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i)
|
||||
{
|
||||
return hash->b[i];
|
||||
}
|
||||
|
||||
static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v)
|
||||
{
|
||||
hash->b[i] = v;
|
||||
}
|
||||
|
||||
static inline void ethash_h256_reset(ethash_h256_t* hash)
|
||||
{
|
||||
memset(hash, 0, 32);
|
||||
}
|
||||
|
||||
// Returns if hash is less than or equal to boundary (2^256/difficulty)
|
||||
static inline bool ethash_check_difficulty(
|
||||
ethash_h256_t const* hash,
|
||||
ethash_h256_t const* boundary
|
||||
)
|
||||
{
|
||||
// Boundary is big endian
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
|
||||
continue;
|
||||
}
|
||||
return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Difficulty quick check for POW preverification
|
||||
*
|
||||
* @param header_hash The hash of the header
|
||||
* @param nonce The block's nonce
|
||||
* @param mix_hash The mix digest hash
|
||||
* @param boundary The boundary is defined as (2^256 / difficulty)
|
||||
* @return true for succesful pre-verification and false otherwise
|
||||
*/
|
||||
bool ethash_quick_check_difficulty(
|
||||
ethash_h256_t const* header_hash,
|
||||
uint64_t const nonce,
|
||||
ethash_h256_t const* mix_hash,
|
||||
ethash_h256_t const* boundary
|
||||
);
|
||||
|
||||
struct ethash_light {
|
||||
void* cache;
|
||||
uint64_t cache_size;
|
||||
uint64_t block_number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new ethash_light handler. Internal version
|
||||
*
|
||||
* @param cache_size The size of the cache in bytes
|
||||
* @param seed Block seedhash to be used during the computation of the
|
||||
* cache nodes
|
||||
* @return Newly allocated ethash_light handler or NULL in case of
|
||||
* ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes()
|
||||
*/
|
||||
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed);
|
||||
|
||||
/**
|
||||
* Calculate the light client data. Internal version.
|
||||
*
|
||||
* @param light The light client handler
|
||||
* @param full_size The size of the full data in bytes.
|
||||
* @param header_hash The header hash to pack into the mix
|
||||
* @param nonce The nonce to pack into the mix
|
||||
* @return The resulting hash.
|
||||
*/
|
||||
ethash_return_value_t ethash_light_compute_internal(
|
||||
ethash_light_t light,
|
||||
uint64_t full_size,
|
||||
ethash_h256_t const header_hash,
|
||||
uint64_t nonce
|
||||
);
|
||||
|
||||
struct ethash_full {
|
||||
FILE* file;
|
||||
uint64_t file_size;
|
||||
node* data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new ethash_full handler. Internal version.
|
||||
*
|
||||
* @param dirname The directory in which to put the DAG file.
|
||||
* @param seedhash The seed hash of the block. Used in the DAG file naming.
|
||||
* @param full_size The size of the full data in bytes.
|
||||
* @param cache A cache object to use that was allocated with @ref ethash_cache_new().
|
||||
* Iff this function succeeds the ethash_full_t will take memory
|
||||
* memory ownership of the cache and free it at deletion. If
|
||||
* not then the user still has to handle freeing of the cache himself.
|
||||
* @param callback A callback function with signature of @ref ethash_callback_t
|
||||
* It accepts an unsigned with which a progress of DAG calculation
|
||||
* can be displayed. If all goes well the callback should return 0.
|
||||
* If a non-zero value is returned then DAG generation will stop.
|
||||
* @return Newly allocated ethash_full handler or NULL in case of
|
||||
* ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
|
||||
*/
|
||||
ethash_full_t ethash_full_new_internal(
|
||||
char const* dirname,
|
||||
ethash_h256_t const seed_hash,
|
||||
uint64_t full_size,
|
||||
ethash_light_t const light,
|
||||
ethash_callback_t callback
|
||||
);
|
||||
|
||||
void ethash_calculate_dag_item(
|
||||
node* const ret,
|
||||
uint32_t node_index,
|
||||
ethash_light_t const cache
|
||||
);
|
||||
|
||||
void ethash_quick_hash(
|
||||
ethash_h256_t* return_hash,
|
||||
ethash_h256_t const* header_hash,
|
||||
const uint64_t nonce,
|
||||
ethash_h256_t const* mix_hash
|
||||
);
|
||||
|
||||
uint64_t ethash_get_datasize(uint64_t const block_number);
|
||||
uint64_t ethash_get_cachesize(uint64_t const block_number);
|
||||
|
||||
/**
|
||||
* Compute the memory data for a full node's memory
|
||||
*
|
||||
* @param mem A pointer to an ethash full's memory
|
||||
* @param full_size The size of the full data in bytes
|
||||
* @param cache A cache object to use in the calculation
|
||||
* @param callback The callback function. Check @ref ethash_full_new() for details.
|
||||
* @return true if all went fine and false for invalid parameters
|
||||
*/
|
||||
bool ethash_compute_full_data(
|
||||
void* mem,
|
||||
uint64_t full_size,
|
||||
ethash_light_t const light,
|
||||
ethash_callback_t callback
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
119
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/io.c
generated
vendored
119
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/io.c
generated
vendored
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
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>
|
||||
#include <errno.h>
|
||||
|
||||
enum ethash_io_rc ethash_io_prepare(
|
||||
char const* dirname,
|
||||
ethash_h256_t const seedhash,
|
||||
FILE** output_file,
|
||||
uint64_t file_size,
|
||||
bool force_create
|
||||
)
|
||||
{
|
||||
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
|
||||
enum ethash_io_rc ret = ETHASH_IO_FAIL;
|
||||
// reset errno before io calls
|
||||
errno = 0;
|
||||
|
||||
// assert directory exists
|
||||
if (!ethash_mkdir(dirname)) {
|
||||
ETHASH_CRITICAL("Could not create the ethash directory");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
|
||||
char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
|
||||
if (!tmpfile) {
|
||||
ETHASH_CRITICAL("Could not create the full DAG pathname");
|
||||
goto end;
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
if (!force_create) {
|
||||
// try to open the file
|
||||
f = ethash_fopen(tmpfile, "rb+");
|
||||
if (f) {
|
||||
size_t found_size;
|
||||
if (!ethash_file_size(f, &found_size)) {
|
||||
fclose(f);
|
||||
ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile);
|
||||
goto free_memo;
|
||||
}
|
||||
if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) {
|
||||
fclose(f);
|
||||
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
|
||||
goto free_memo;
|
||||
}
|
||||
// compare the magic number, no need to care about endianess since it's local
|
||||
uint64_t magic_num;
|
||||
if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
|
||||
// I/O error
|
||||
fclose(f);
|
||||
ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile);
|
||||
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
|
||||
goto free_memo;
|
||||
}
|
||||
if (magic_num != ETHASH_DAG_MAGIC_NUM) {
|
||||
fclose(f);
|
||||
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
|
||||
goto free_memo;
|
||||
}
|
||||
ret = ETHASH_IO_MEMO_MATCH;
|
||||
goto set_file;
|
||||
}
|
||||
}
|
||||
|
||||
// file does not exist, will need to be created
|
||||
f = ethash_fopen(tmpfile, "wb+");
|
||||
if (!f) {
|
||||
ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile);
|
||||
goto free_memo;
|
||||
}
|
||||
// make sure it's of the proper size
|
||||
if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
|
||||
fclose(f);
|
||||
ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
||||
goto free_memo;
|
||||
}
|
||||
if (fputc('\n', f) == EOF) {
|
||||
fclose(f);
|
||||
ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
||||
goto free_memo;
|
||||
}
|
||||
if (fflush(f) != 0) {
|
||||
fclose(f);
|
||||
ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile);
|
||||
goto free_memo;
|
||||
}
|
||||
ret = ETHASH_IO_MEMO_MISMATCH;
|
||||
goto set_file;
|
||||
|
||||
ret = ETHASH_IO_MEMO_MATCH;
|
||||
set_file:
|
||||
*output_file = f;
|
||||
free_memo:
|
||||
free(tmpfile);
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
202
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/io.h
generated
vendored
202
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/io.h
generated
vendored
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
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 <stdio.h>
|
||||
#ifdef __cplusplus
|
||||
#define __STDC_FORMAT_MACROS 1
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#include "endian.h"
|
||||
#include "ethash.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// Maximum size for mutable part of DAG file name
|
||||
// 6 is for "full-R", the suffix of the filename
|
||||
// 10 is for maximum number of digits of a uint32_t (for REVISION)
|
||||
// 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of
|
||||
// the seedhash and last 1 is for the null terminating character
|
||||
// Reference: https://github.com/expanse-org/wiki/wiki/Ethash-DAG
|
||||
#define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1)
|
||||
/// 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_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong.
|
||||
ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch
|
||||
ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything
|
||||
};
|
||||
|
||||
// small hack for windows. I don't feel I should use va_args and forward just
|
||||
// to have this one function properly cross-platform abstracted
|
||||
#if defined(_WIN32) && !defined(__GNUC__)
|
||||
#define snprintf(...) sprintf_s(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Logs a critical error in important parts of ethash. Should mostly help
|
||||
* figure out what kind of problem (I/O, memory e.t.c.) causes a NULL
|
||||
* ethash_full_t
|
||||
*/
|
||||
#ifdef ETHASH_PRINT_CRITICAL_OUTPUT
|
||||
#define ETHASH_CRITICAL(...) \
|
||||
do \
|
||||
{ \
|
||||
printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
fflush(stdout); \
|
||||
} while (0)
|
||||
#else
|
||||
#define ETHASH_CRITICAL(...)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Prepares io for ethash
|
||||
*
|
||||
* Create the DAG directory and the DAG file if they don't exist.
|
||||
*
|
||||
* @param[in] dirname A null terminated c-string of the path of the ethash
|
||||
* data directory. If it does not exist it's created.
|
||||
* @param[in] seedhash The seedhash of the current block number, used in the
|
||||
* naming of the file as can be seen from the spec at:
|
||||
* https://github.com/expanse-org/wiki/wiki/Ethash-DAG
|
||||
* @param[out] output_file If there was no failure then this will point to an open
|
||||
* file descriptor. User is responsible for closing it.
|
||||
* In the case of memo match then the file is open on read
|
||||
* mode, while on the case of mismatch a new file is created
|
||||
* on write mode
|
||||
* @param[in] file_size The size that the DAG file should have on disk
|
||||
* @param[out] force_create If true then there is no check to see if the file
|
||||
* already exists
|
||||
* @return For possible return values @see enum ethash_io_rc
|
||||
*/
|
||||
enum ethash_io_rc ethash_io_prepare(
|
||||
char const* dirname,
|
||||
ethash_h256_t const seedhash,
|
||||
FILE** output_file,
|
||||
uint64_t file_size,
|
||||
bool force_create
|
||||
);
|
||||
|
||||
/**
|
||||
* An fopen wrapper for no-warnings crossplatform fopen.
|
||||
*
|
||||
* Msvc compiler considers fopen to be insecure and suggests to use their
|
||||
* alternative. This is a wrapper for this alternative. Another way is to
|
||||
* #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
|
||||
* not sound like a good idea.
|
||||
*
|
||||
* @param file_name The path to the file to open
|
||||
* @param mode Opening mode. Check fopen()
|
||||
* @return The FILE* or NULL in failure
|
||||
*/
|
||||
FILE* ethash_fopen(char const* file_name, char const* mode);
|
||||
|
||||
/**
|
||||
* An strncat wrapper for no-warnings crossplatform strncat.
|
||||
*
|
||||
* Msvc compiler considers strncat to be insecure and suggests to use their
|
||||
* alternative. This is a wrapper for this alternative. Another way is to
|
||||
* #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
|
||||
* not sound like a good idea.
|
||||
*
|
||||
* @param des Destination buffer
|
||||
* @param dest_size Maximum size of the destination buffer. This is the
|
||||
* extra argument for the MSVC secure strncat
|
||||
* @param src Souce buffer
|
||||
* @param count Number of bytes to copy from source
|
||||
* @return If all is well returns the dest buffer. If there is an
|
||||
* error returns NULL
|
||||
*/
|
||||
char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count);
|
||||
|
||||
/**
|
||||
* A cross-platform mkdir wrapper to create a directory or assert it's there
|
||||
*
|
||||
* @param dirname The full path of the directory to create
|
||||
* @return true if the directory was created or if it already
|
||||
* existed
|
||||
*/
|
||||
bool ethash_mkdir(char const* dirname);
|
||||
|
||||
/**
|
||||
* Get a file's size
|
||||
*
|
||||
* @param[in] f The open file stream whose size to get
|
||||
* @param[out] size Pass a size_t by reference to contain the file size
|
||||
* @return true in success and false if there was a failure
|
||||
*/
|
||||
bool ethash_file_size(FILE* f, size_t* ret_size);
|
||||
|
||||
/**
|
||||
* Get a file descriptor number from a FILE stream
|
||||
*
|
||||
* @param f The file stream whose fd to get
|
||||
* @return Platform specific fd handler
|
||||
*/
|
||||
int ethash_fileno(FILE* f);
|
||||
|
||||
/**
|
||||
* Create the filename for the DAG.
|
||||
*
|
||||
* @param dirname The directory name in which the DAG file should reside
|
||||
* If it does not end with a directory separator it is appended.
|
||||
* @param filename The actual name of the file
|
||||
* @param filename_length The length of the filename in bytes
|
||||
* @return A char* containing the full name. User must deallocate.
|
||||
*/
|
||||
char* ethash_io_create_filename(
|
||||
char const* dirname,
|
||||
char const* filename,
|
||||
size_t filename_length
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the default directory name for the DAG depending on the system
|
||||
*
|
||||
* The spec defining this directory is here: https://github.com/expanse-org/wiki/wiki/Ethash-DAG
|
||||
*
|
||||
* @param[out] strbuf A string buffer of sufficient size to keep the
|
||||
* null termninated string of the directory name
|
||||
* @param[in] buffsize Size of @a strbuf in bytes
|
||||
* @return true for success and false otherwise
|
||||
*/
|
||||
bool ethash_get_default_dirname(char* strbuf, size_t buffsize);
|
||||
|
||||
static inline bool ethash_io_mutable_name(
|
||||
uint32_t revision,
|
||||
ethash_h256_t const* seed_hash,
|
||||
char* output
|
||||
)
|
||||
{
|
||||
uint64_t hash = *((uint64_t*)seed_hash);
|
||||
#if LITTLE_ENDIAN == BYTE_ORDER
|
||||
hash = ethash_swap_u64(hash);
|
||||
#endif
|
||||
return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
111
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/io_posix.c
generated
vendored
111
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/io_posix.c
generated
vendored
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
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>
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
|
||||
FILE* ethash_fopen(char const* file_name, char const* mode)
|
||||
{
|
||||
return fopen(file_name, mode);
|
||||
}
|
||||
|
||||
char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count)
|
||||
{
|
||||
return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL;
|
||||
}
|
||||
|
||||
bool ethash_mkdir(char const* dirname)
|
||||
{
|
||||
int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
return rc != -1 || errno == EEXIST;
|
||||
}
|
||||
|
||||
int ethash_fileno(FILE *f)
|
||||
{
|
||||
return fileno(f);
|
||||
}
|
||||
|
||||
char* ethash_io_create_filename(
|
||||
char const* dirname,
|
||||
char const* filename,
|
||||
size_t filename_length
|
||||
)
|
||||
{
|
||||
size_t dirlen = strlen(dirname);
|
||||
size_t dest_size = dirlen + filename_length + 1;
|
||||
if (dirname[dirlen] != '/') {
|
||||
dest_size += 1;
|
||||
}
|
||||
char* name = malloc(dest_size);
|
||||
if (!name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name[0] = '\0';
|
||||
ethash_strncat(name, dest_size, dirname, dirlen);
|
||||
if (dirname[dirlen] != '/') {
|
||||
ethash_strncat(name, dest_size, "/", 1);
|
||||
}
|
||||
ethash_strncat(name, dest_size, filename, filename_length);
|
||||
return name;
|
||||
}
|
||||
|
||||
bool ethash_file_size(FILE* f, size_t* ret_size)
|
||||
{
|
||||
struct stat st;
|
||||
int fd;
|
||||
if ((fd = fileno(f)) == -1 || fstat(fd, &st) != 0) {
|
||||
return false;
|
||||
}
|
||||
*ret_size = st.st_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
|
||||
{
|
||||
static const char dir_suffix[] = ".ethash/";
|
||||
strbuf[0] = '\0';
|
||||
char* home_dir = getenv("HOME");
|
||||
if (!home_dir || strlen(home_dir) == 0)
|
||||
{
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd)
|
||||
home_dir = pwd->pw_dir;
|
||||
}
|
||||
|
||||
size_t len = strlen(home_dir);
|
||||
if (!ethash_strncat(strbuf, buffsize, home_dir, len)) {
|
||||
return false;
|
||||
}
|
||||
if (home_dir[len] != '/') {
|
||||
if (!ethash_strncat(strbuf, buffsize, "/", 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix));
|
||||
}
|
||||
100
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/io_win32.c
generated
vendored
100
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/io_win32.c
generated
vendored
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
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>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
FILE* ethash_fopen(char const* file_name, char const* mode)
|
||||
{
|
||||
FILE* f;
|
||||
return fopen_s(&f, file_name, mode) == 0 ? f : NULL;
|
||||
}
|
||||
|
||||
char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count)
|
||||
{
|
||||
return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL;
|
||||
}
|
||||
|
||||
bool ethash_mkdir(char const* dirname)
|
||||
{
|
||||
int rc = _mkdir(dirname);
|
||||
return rc != -1 || errno == EEXIST;
|
||||
}
|
||||
|
||||
int ethash_fileno(FILE* f)
|
||||
{
|
||||
return _fileno(f);
|
||||
}
|
||||
|
||||
char* ethash_io_create_filename(
|
||||
char const* dirname,
|
||||
char const* filename,
|
||||
size_t filename_length
|
||||
)
|
||||
{
|
||||
size_t dirlen = strlen(dirname);
|
||||
size_t dest_size = dirlen + filename_length + 1;
|
||||
if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') {
|
||||
dest_size += 1;
|
||||
}
|
||||
char* name = malloc(dest_size);
|
||||
if (!name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name[0] = '\0';
|
||||
ethash_strncat(name, dest_size, dirname, dirlen);
|
||||
if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') {
|
||||
ethash_strncat(name, dest_size, "\\", 1);
|
||||
}
|
||||
ethash_strncat(name, dest_size, filename, filename_length);
|
||||
return name;
|
||||
}
|
||||
|
||||
bool ethash_file_size(FILE* f, size_t* ret_size)
|
||||
{
|
||||
struct _stat st;
|
||||
int fd;
|
||||
if ((fd = _fileno(f)) == -1 || _fstat(fd, &st) != 0) {
|
||||
return false;
|
||||
}
|
||||
*ret_size = st.st_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
|
||||
{
|
||||
static const char dir_suffix[] = "Ethash\\";
|
||||
strbuf[0] = '\0';
|
||||
if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) {
|
||||
return false;
|
||||
}
|
||||
if (!ethash_strncat(strbuf, buffsize, "\\", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix));
|
||||
}
|
||||
47
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/mmap.h
generated
vendored
47
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/mmap.h
generated
vendored
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
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 mmap.h
|
||||
* @author Lefteris Karapetsas <lefteris@ethdev.com>
|
||||
* @date 2015
|
||||
*/
|
||||
#pragma once
|
||||
#if defined(__MINGW32__) || defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
|
||||
#define PROT_READ 0x1
|
||||
#define PROT_WRITE 0x2
|
||||
/* This flag is only available in WinXP+ */
|
||||
#ifdef FILE_MAP_EXECUTE
|
||||
#define PROT_EXEC 0x4
|
||||
#else
|
||||
#define PROT_EXEC 0x0
|
||||
#define FILE_MAP_EXECUTE 0
|
||||
#endif
|
||||
|
||||
#define MAP_SHARED 0x01
|
||||
#define MAP_PRIVATE 0x02
|
||||
#define MAP_ANONYMOUS 0x20
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
|
||||
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
|
||||
void munmap(void* addr, size_t length);
|
||||
#else // posix, yay! ^_^
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
|
||||
84
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/mmap_win32.c
generated
vendored
84
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/mmap_win32.c
generated
vendored
|
|
@ -1,84 +0,0 @@
|
|||
/* mmap() replacement for Windows
|
||||
*
|
||||
* Author: Mike Frysinger <vapier@gentoo.org>
|
||||
* Placed into the public domain
|
||||
*/
|
||||
|
||||
/* References:
|
||||
* CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
|
||||
* CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
|
||||
* MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
|
||||
* UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
|
||||
*/
|
||||
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#include "mmap.h"
|
||||
|
||||
#ifdef __USE_FILE_OFFSET64
|
||||
# define DWORD_HI(x) (x >> 32)
|
||||
# define DWORD_LO(x) ((x) & 0xffffffff)
|
||||
#else
|
||||
# define DWORD_HI(x) (0)
|
||||
# define DWORD_LO(x) (x)
|
||||
#endif
|
||||
|
||||
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset)
|
||||
{
|
||||
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
return MAP_FAILED;
|
||||
if (fd == -1) {
|
||||
if (!(flags & MAP_ANON) || offset)
|
||||
return MAP_FAILED;
|
||||
} else if (flags & MAP_ANON)
|
||||
return MAP_FAILED;
|
||||
|
||||
DWORD flProtect;
|
||||
if (prot & PROT_WRITE) {
|
||||
if (prot & PROT_EXEC)
|
||||
flProtect = PAGE_EXECUTE_READWRITE;
|
||||
else
|
||||
flProtect = PAGE_READWRITE;
|
||||
} else if (prot & PROT_EXEC) {
|
||||
if (prot & PROT_READ)
|
||||
flProtect = PAGE_EXECUTE_READ;
|
||||
else if (prot & PROT_EXEC)
|
||||
flProtect = PAGE_EXECUTE;
|
||||
} else
|
||||
flProtect = PAGE_READONLY;
|
||||
|
||||
off_t end = length + offset;
|
||||
HANDLE mmap_fd, h;
|
||||
if (fd == -1)
|
||||
mmap_fd = INVALID_HANDLE_VALUE;
|
||||
else
|
||||
mmap_fd = (HANDLE)_get_osfhandle(fd);
|
||||
h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
|
||||
if (h == NULL)
|
||||
return MAP_FAILED;
|
||||
|
||||
DWORD dwDesiredAccess;
|
||||
if (prot & PROT_WRITE)
|
||||
dwDesiredAccess = FILE_MAP_WRITE;
|
||||
else
|
||||
dwDesiredAccess = FILE_MAP_READ;
|
||||
if (prot & PROT_EXEC)
|
||||
dwDesiredAccess |= FILE_MAP_EXECUTE;
|
||||
if (flags & MAP_PRIVATE)
|
||||
dwDesiredAccess |= FILE_MAP_COPY;
|
||||
void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
|
||||
if (ret == NULL) {
|
||||
ret = MAP_FAILED;
|
||||
}
|
||||
// since we are handling the file ourselves with fd, close the Windows Handle here
|
||||
CloseHandle(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void munmap(void* addr, size_t length)
|
||||
{
|
||||
UnmapViewOfFile(addr);
|
||||
}
|
||||
|
||||
#undef DWORD_HI
|
||||
#undef DWORD_LO
|
||||
151
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/sha3.c
generated
vendored
151
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/sha3.c
generated
vendored
|
|
@ -1,151 +0,0 @@
|
|||
/** libkeccak-tiny
|
||||
*
|
||||
* A single-file implementation of SHA-3 and SHAKE.
|
||||
*
|
||||
* Implementor: David Leon Gil
|
||||
* License: CC0, attribution kindly requested. Blame taken too,
|
||||
* but not liability.
|
||||
*/
|
||||
#include "sha3.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/******** The Keccak-f[1600] permutation ********/
|
||||
|
||||
/*** Constants. ***/
|
||||
static const uint8_t rho[24] = \
|
||||
{ 1, 3, 6, 10, 15, 21,
|
||||
28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43,
|
||||
62, 18, 39, 61, 20, 44};
|
||||
static const uint8_t pi[24] = \
|
||||
{10, 7, 11, 17, 18, 3,
|
||||
5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2,
|
||||
20, 14, 22, 9, 6, 1};
|
||||
static const uint64_t RC[24] = \
|
||||
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
|
||||
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
|
||||
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
|
||||
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
|
||||
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
|
||||
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
|
||||
|
||||
/*** Helper macros to unroll the permutation. ***/
|
||||
#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
|
||||
#define REPEAT6(e) e e e e e e
|
||||
#define REPEAT24(e) REPEAT6(e e e e)
|
||||
#define REPEAT5(e) e e e e e
|
||||
#define FOR5(v, s, e) \
|
||||
v = 0; \
|
||||
REPEAT5(e; v += s;)
|
||||
|
||||
/*** Keccak-f[1600] ***/
|
||||
static inline void keccakf(void* state) {
|
||||
uint64_t* a = (uint64_t*)state;
|
||||
uint64_t b[5] = {0};
|
||||
uint64_t t = 0;
|
||||
uint8_t x, y;
|
||||
|
||||
for (int i = 0; i < 24; i++) {
|
||||
// Theta
|
||||
FOR5(x, 1,
|
||||
b[x] = 0;
|
||||
FOR5(y, 5,
|
||||
b[x] ^= a[x + y]; ))
|
||||
FOR5(x, 1,
|
||||
FOR5(y, 5,
|
||||
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
|
||||
// Rho and pi
|
||||
t = a[1];
|
||||
x = 0;
|
||||
REPEAT24(b[0] = a[pi[x]];
|
||||
a[pi[x]] = rol(t, rho[x]);
|
||||
t = b[0];
|
||||
x++; )
|
||||
// Chi
|
||||
FOR5(y,
|
||||
5,
|
||||
FOR5(x, 1,
|
||||
b[x] = a[y + x];)
|
||||
FOR5(x, 1,
|
||||
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
|
||||
// Iota
|
||||
a[0] ^= RC[i];
|
||||
}
|
||||
}
|
||||
|
||||
/******** The FIPS202-defined functions. ********/
|
||||
|
||||
/*** Some helper macros. ***/
|
||||
|
||||
#define _(S) do { S } while (0)
|
||||
#define FOR(i, ST, L, S) \
|
||||
_(for (size_t i = 0; i < L; i += ST) { S; })
|
||||
#define mkapply_ds(NAME, S) \
|
||||
static inline void NAME(uint8_t* dst, \
|
||||
const uint8_t* src, \
|
||||
size_t len) { \
|
||||
FOR(i, 1, len, S); \
|
||||
}
|
||||
#define mkapply_sd(NAME, S) \
|
||||
static inline void NAME(const uint8_t* src, \
|
||||
uint8_t* dst, \
|
||||
size_t len) { \
|
||||
FOR(i, 1, len, S); \
|
||||
}
|
||||
|
||||
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
|
||||
mkapply_sd(setout, dst[i] = src[i]) // setout
|
||||
|
||||
#define P keccakf
|
||||
#define Plen 200
|
||||
|
||||
// Fold P*F over the full blocks of an input.
|
||||
#define foldP(I, L, F) \
|
||||
while (L >= rate) { \
|
||||
F(a, I, rate); \
|
||||
P(a); \
|
||||
I += rate; \
|
||||
L -= rate; \
|
||||
}
|
||||
|
||||
/** The sponge-based hash construction. **/
|
||||
static inline int hash(uint8_t* out, size_t outlen,
|
||||
const uint8_t* in, size_t inlen,
|
||||
size_t rate, uint8_t delim) {
|
||||
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
|
||||
return -1;
|
||||
}
|
||||
uint8_t a[Plen] = {0};
|
||||
// Absorb input.
|
||||
foldP(in, inlen, xorin);
|
||||
// Xor in the DS and pad frame.
|
||||
a[inlen] ^= delim;
|
||||
a[rate - 1] ^= 0x80;
|
||||
// Xor in the last block.
|
||||
xorin(a, in, inlen);
|
||||
// Apply P
|
||||
P(a);
|
||||
// Squeeze output.
|
||||
foldP(out, outlen, setout);
|
||||
setout(a, out, outlen);
|
||||
memset(a, 0, 200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define defsha3(bits) \
|
||||
int sha3_##bits(uint8_t* out, size_t outlen, \
|
||||
const uint8_t* in, size_t inlen) { \
|
||||
if (outlen > (bits/8)) { \
|
||||
return -1; \
|
||||
} \
|
||||
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
|
||||
}
|
||||
|
||||
/*** FIPS202 SHA3 FOFs ***/
|
||||
defsha3(256)
|
||||
defsha3(512)
|
||||
31
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/sha3.h
generated
vendored
31
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/sha3.h
generated
vendored
|
|
@ -1,31 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "compiler.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct ethash_h256;
|
||||
|
||||
#define decsha3(bits) \
|
||||
int sha3_##bits(uint8_t*, size_t, uint8_t const*, size_t);
|
||||
|
||||
decsha3(256)
|
||||
decsha3(512)
|
||||
|
||||
static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t const size)
|
||||
{
|
||||
sha3_256((uint8_t*)ret, 32, data, size);
|
||||
}
|
||||
|
||||
static inline void SHA3_512(uint8_t* ret, uint8_t const* data, size_t const size)
|
||||
{
|
||||
sha3_512(ret, 64, data, size);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
37
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/sha3_cryptopp.cpp
generated
vendored
37
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/sha3_cryptopp.cpp
generated
vendored
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
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 sha3.cpp
|
||||
* @author Tim Hughes <tim@twistedfury.com>
|
||||
* @date 2015
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <cryptopp/sha3.h>
|
||||
|
||||
extern "C" {
|
||||
struct ethash_h256;
|
||||
typedef struct ethash_h256 ethash_h256_t;
|
||||
void SHA3_256(ethash_h256_t const* ret, uint8_t const* data, size_t size)
|
||||
{
|
||||
CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size);
|
||||
}
|
||||
|
||||
void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size)
|
||||
{
|
||||
CryptoPP::SHA3_512().CalculateDigest(ret, data, size);
|
||||
}
|
||||
}
|
||||
18
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/sha3_cryptopp.h
generated
vendored
18
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/sha3_cryptopp.h
generated
vendored
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "compiler.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ethash_h256;
|
||||
|
||||
void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t size);
|
||||
void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
47
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/util.h
generated
vendored
47
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/util.h
generated
vendored
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
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 util.h
|
||||
* @author Tim Hughes <tim@twistedfury.com>
|
||||
* @date 2015
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
void debugf(char const* str, ...);
|
||||
#else
|
||||
#define debugf printf
|
||||
#endif
|
||||
|
||||
static inline uint32_t min_u32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static inline uint32_t clamp_u32(uint32_t x, uint32_t min_, uint32_t max_)
|
||||
{
|
||||
return x < min_ ? min_ : (x > max_ ? max_ : x);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
38
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/util_win32.c
generated
vendored
38
Godeps/_workspace/src/github.com/expanse-org/ethash/src/libethash/util_win32.c
generated
vendored
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
This file is part of cpp-expanse.
|
||||
|
||||
cpp-expanse is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-expanse is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-expanse. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file util.c
|
||||
* @author Tim Hughes <tim@twistedfury.com>
|
||||
* @date 2015
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "util.h"
|
||||
|
||||
|
||||
// foward declare without all of Windows.h
|
||||
__declspec(dllimport) void __stdcall OutputDebugStringA(char const* lpOutputString);
|
||||
|
||||
void debugf(char const* str, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
|
||||
char buf[1<<16];
|
||||
_vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args);
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
OutputDebugStringA(buf);
|
||||
}
|
||||
267
Godeps/_workspace/src/github.com/expanse-org/ethash/src/python/core.c
generated
vendored
267
Godeps/_workspace/src/github.com/expanse-org/ethash/src/python/core.c
generated
vendored
|
|
@ -1,267 +0,0 @@
|
|||
#include <Python.h>
|
||||
#include <alloca.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "../libethash/ethash.h"
|
||||
#include "../libethash/internal.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 (ETHASH_MIX_BYTES/4)
|
||||
|
||||
static PyObject *
|
||||
mkcache_bytes(PyObject *self, PyObject *args) {
|
||||
unsigned long block_number;
|
||||
unsigned long cache_size;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "k", &block_number))
|
||||
return 0;
|
||||
|
||||
ethash_light_t L = ethash_light_new(block_number);
|
||||
PyObject * val = Py_BuildValue(PY_STRING_FORMAT, L->cache, L->cache_size);
|
||||
free(L->cache);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
static PyObject *
|
||||
calc_dataset_bytes(PyObject *self, PyObject *args) {
|
||||
char *cache_bytes;
|
||||
unsigned long full_size;
|
||||
int cache_size;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT, &full_size, &cache_bytes, &cache_size))
|
||||
return 0;
|
||||
|
||||
if (full_size % MIX_WORDS != 0) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %lu)", MIX_WORDS, full_size);
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cache_size % ETHASH_HASH_BYTES != 0) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "The size of the cache must be a multiple of %i bytes (was %i)", ETHASH_HASH_BYTES, cache_size);
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ethash_params params;
|
||||
params.cache_size = (size_t) cache_size;
|
||||
params.full_size = (size_t) full_size;
|
||||
ethash_cache cache;
|
||||
cache.mem = (void *) cache_bytes;
|
||||
void *mem = malloc(params.full_size);
|
||||
ethash_compute_full_data(mem, ¶ms, &cache);
|
||||
PyObject * val = Py_BuildValue(PY_STRING_FORMAT, (char *) mem, full_size);
|
||||
free(mem);
|
||||
return val;
|
||||
}*/
|
||||
|
||||
// hashimoto_light(full_size, cache, header, nonce)
|
||||
static PyObject *
|
||||
hashimoto_light(PyObject *self, PyObject *args) {
|
||||
char *cache_bytes;
|
||||
char *header;
|
||||
unsigned long block_number;
|
||||
unsigned long long nonce;
|
||||
int cache_size, header_size;
|
||||
if (!PyArg_ParseTuple(args, "k" PY_STRING_FORMAT PY_STRING_FORMAT "K", &block_number, &cache_bytes, &cache_size, &header, &header_size, &nonce))
|
||||
return 0;
|
||||
if (header_size != 32) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "Seed must be 32 bytes long (was %i)", header_size);
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
struct ethash_light *s;
|
||||
s = calloc(sizeof(*s), 1);
|
||||
s->cache = cache_bytes;
|
||||
s->cache_size = cache_size;
|
||||
s->block_number = block_number;
|
||||
struct ethash_h256 *h;
|
||||
h = calloc(sizeof(*h), 1);
|
||||
for (int i = 0; i < 32; i++) h->b[i] = header[i];
|
||||
struct ethash_return_value out = ethash_light_compute(s, *h, nonce);
|
||||
return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "," PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "}",
|
||||
"mix digest", &out.mix_hash, 32,
|
||||
"result", &out.result, 32);
|
||||
}
|
||||
/*
|
||||
// hashimoto_full(dataset, header, nonce)
|
||||
static PyObject *
|
||||
hashimoto_full(PyObject *self, PyObject *args) {
|
||||
char *full_bytes;
|
||||
char *header;
|
||||
unsigned long long nonce;
|
||||
int full_size, header_size;
|
||||
|
||||
if (!PyArg_ParseTuple(args, PY_STRING_FORMAT PY_STRING_FORMAT "K", &full_bytes, &full_size, &header, &header_size, &nonce))
|
||||
return 0;
|
||||
|
||||
if (full_size % MIX_WORDS != 0) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %i)", MIX_WORDS, full_size);
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (header_size != 32) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "Header must be 32 bytes long (was %i)", header_size);
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ethash_return_value out;
|
||||
ethash_params params;
|
||||
params.full_size = (size_t) full_size;
|
||||
ethash_full(&out, (void *) full_bytes, ¶ms, (ethash_h256_t *) header, nonce);
|
||||
return Py_BuildValue("{" PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT ", " PY_CONST_STRING_FORMAT ":" PY_STRING_FORMAT "}",
|
||||
"mix digest", &out.mix_hash, 32,
|
||||
"result", &out.result, 32);
|
||||
}
|
||||
|
||||
// mine(dataset_bytes, header, difficulty_bytes)
|
||||
static PyObject *
|
||||
mine(PyObject *self, PyObject *args) {
|
||||
char *full_bytes;
|
||||
char *header;
|
||||
char *difficulty;
|
||||
srand(time(0));
|
||||
uint64_t nonce = ((uint64_t) rand()) << 32 | rand();
|
||||
int full_size, header_size, 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;
|
||||
|
||||
if (full_size % MIX_WORDS != 0) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %i)", MIX_WORDS, full_size);
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (header_size != 32) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "Header must be 32 bytes long (was %i)", header_size);
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (difficulty_size != 32) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "Difficulty must be an array of 32 bytes (only had %i)", difficulty_size);
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ethash_return_value out;
|
||||
ethash_params params;
|
||||
params.full_size = (size_t) full_size;
|
||||
|
||||
// TODO: Multi threading?
|
||||
do {
|
||||
ethash_full(&out, (void *) full_bytes, ¶ms, (const ethash_h256_t *) header, nonce++);
|
||||
// TODO: disagrees with the spec https://github.com/expanse-org/wiki/wiki/Ethash#mining
|
||||
} while (!ethash_check_difficulty(&out.result, (const ethash_h256_t *) difficulty));
|
||||
|
||||
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,
|
||||
"result", &out.result, 32,
|
||||
"nonce", nonce);
|
||||
}
|
||||
*/
|
||||
|
||||
//get_seedhash(block_number)
|
||||
static PyObject *
|
||||
get_seedhash(PyObject *self, PyObject *args) {
|
||||
unsigned long block_number;
|
||||
if (!PyArg_ParseTuple(args, "k", &block_number))
|
||||
return 0;
|
||||
if (block_number >= ETHASH_EPOCH_LENGTH * 2048) {
|
||||
char error_message[1024];
|
||||
sprintf(error_message, "Block number must be less than %i (was %lu)", ETHASH_EPOCH_LENGTH * 2048, block_number);
|
||||
|
||||
PyErr_SetString(PyExc_ValueError, error_message);
|
||||
return 0;
|
||||
}
|
||||
ethash_h256_t seedhash = ethash_get_seedhash(block_number);
|
||||
return Py_BuildValue(PY_STRING_FORMAT, (char *) &seedhash, 32);
|
||||
}
|
||||
|
||||
static PyMethodDef PyethashMethods[] =
|
||||
{
|
||||
{"get_seedhash", get_seedhash, METH_VARARGS,
|
||||
"get_seedhash(block_number)\n\n"
|
||||
"Gets the seedhash for a block."},
|
||||
{"mkcache_bytes", mkcache_bytes, METH_VARARGS,
|
||||
"mkcache_bytes(block_number)\n\n"
|
||||
"Makes a byte array for the cache for given block number\n"},
|
||||
/*{"calc_dataset_bytes", calc_dataset_bytes, METH_VARARGS,
|
||||
"calc_dataset_bytes(full_size, cache_bytes)\n\n"
|
||||
"Makes a byte array for the dataset for a given size given cache bytes"},*/
|
||||
{"hashimoto_light", hashimoto_light, METH_VARARGS,
|
||||
"hashimoto_light(block_number, cache_bytes, header, nonce)\n\n"
|
||||
"Runs the hashimoto hashing function just using cache bytes. Takes an int (full_size), byte array (cache_bytes), another byte array (header), and an int (nonce). Returns an object containing the mix digest, and hash result."},
|
||||
/*{"hashimoto_full", hashimoto_full, METH_VARARGS,
|
||||
"hashimoto_full(dataset_bytes, header, nonce)\n\n"
|
||||
"Runs the hashimoto hashing function using the dataset bytes. Useful for testing. Returns an object containing the mix digest (byte array), and hash result (another byte array)."},
|
||||
{"mine", mine, METH_VARARGS,
|
||||
"mine(dataset_bytes, header, difficulty_bytes)\n\n"
|
||||
"Mine for an adequate header. Returns an object containing the mix digest (byte array), hash result (another byte array) and nonce (an int)."},*/
|
||||
{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/expanse-org/wiki/wiki/Ethash#definitions
|
||||
PyModule_AddIntConstant(module, "REVISION", (long) ETHASH_REVISION);
|
||||
PyModule_AddIntConstant(module, "DATASET_BYTES_INIT", (long) ETHASH_DATASET_BYTES_INIT);
|
||||
PyModule_AddIntConstant(module, "DATASET_BYTES_GROWTH", (long) ETHASH_DATASET_BYTES_GROWTH);
|
||||
PyModule_AddIntConstant(module, "CACHE_BYTES_INIT", (long) ETHASH_CACHE_BYTES_INIT);
|
||||
PyModule_AddIntConstant(module, "CACHE_BYTES_GROWTH", (long) ETHASH_CACHE_BYTES_GROWTH);
|
||||
PyModule_AddIntConstant(module, "EPOCH_LENGTH", (long) ETHASH_EPOCH_LENGTH);
|
||||
PyModule_AddIntConstant(module, "MIX_BYTES", (long) ETHASH_MIX_BYTES);
|
||||
PyModule_AddIntConstant(module, "HASH_BYTES", (long) ETHASH_HASH_BYTES);
|
||||
PyModule_AddIntConstant(module, "DATASET_PARENTS", (long) ETHASH_DATASET_PARENTS);
|
||||
PyModule_AddIntConstant(module, "CACHE_ROUNDS", (long) ETHASH_CACHE_ROUNDS);
|
||||
PyModule_AddIntConstant(module, "ACCESSES", (long) ETHASH_ACCESSES);
|
||||
return module;
|
||||
}
|
||||
#else
|
||||
PyMODINIT_FUNC
|
||||
initpyethash(void) {
|
||||
PyObject *module = Py_InitModule("pyethash", PyethashMethods);
|
||||
// Following Spec: https://github.com/expanse-org/wiki/wiki/Ethash#definitions
|
||||
PyModule_AddIntConstant(module, "REVISION", (long) ETHASH_REVISION);
|
||||
PyModule_AddIntConstant(module, "DATASET_BYTES_INIT", (long) ETHASH_DATASET_BYTES_INIT);
|
||||
PyModule_AddIntConstant(module, "DATASET_BYTES_GROWTH", (long) ETHASH_DATASET_BYTES_GROWTH);
|
||||
PyModule_AddIntConstant(module, "CACHE_BYTES_INIT", (long) ETHASH_CACHE_BYTES_INIT);
|
||||
PyModule_AddIntConstant(module, "CACHE_BYTES_GROWTH", (long) ETHASH_CACHE_BYTES_GROWTH);
|
||||
PyModule_AddIntConstant(module, "EPOCH_LENGTH", (long) ETHASH_EPOCH_LENGTH);
|
||||
PyModule_AddIntConstant(module, "MIX_BYTES", (long) ETHASH_MIX_BYTES);
|
||||
PyModule_AddIntConstant(module, "HASH_BYTES", (long) ETHASH_HASH_BYTES);
|
||||
PyModule_AddIntConstant(module, "DATASET_PARENTS", (long) ETHASH_DATASET_PARENTS);
|
||||
PyModule_AddIntConstant(module, "CACHE_ROUNDS", (long) ETHASH_CACHE_ROUNDS);
|
||||
PyModule_AddIntConstant(module, "ACCESSES", (long) ETHASH_ACCESSES);
|
||||
}
|
||||
#endif
|
||||
66
Godeps/_workspace/src/github.com/expanse-org/ethash/test/c/CMakeLists.txt
generated
vendored
66
Godeps/_workspace/src/github.com/expanse-org/ethash/test/c/CMakeLists.txt
generated
vendored
|
|
@ -1,66 +0,0 @@
|
|||
if (MSVC)
|
||||
if (NOT BOOST_ROOT)
|
||||
set (BOOST_ROOT "$ENV{BOOST_ROOT}")
|
||||
endif()
|
||||
set (CMAKE_PREFIX_PATH BOOST_ROOT)
|
||||
endif()
|
||||
|
||||
IF( NOT Boost_FOUND )
|
||||
# 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()
|
||||
|
||||
IF (Boost_FOUND)
|
||||
message(STATUS "boost header: ${Boost_INCLUDE_DIRS}")
|
||||
message(STATUS "boost libs : ${Boost_LIBRARIES}")
|
||||
|
||||
include_directories( ${Boost_INCLUDE_DIR} )
|
||||
include_directories(../../src)
|
||||
|
||||
link_directories(${Boost_LIBRARY_DIRS})
|
||||
file(GLOB HEADERS "*.h")
|
||||
if ((NOT MSVC) AND (NOT APPLE))
|
||||
ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK)
|
||||
endif()
|
||||
if (NOT CRYPTOPP_FOUND)
|
||||
find_package (CryptoPP)
|
||||
endif()
|
||||
|
||||
if (CRYPTOPP_FOUND)
|
||||
add_definitions(-DWITH_CRYPTOPP)
|
||||
endif()
|
||||
|
||||
if (NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
|
||||
endif()
|
||||
|
||||
add_executable (Test "./test.cpp" ${HEADERS})
|
||||
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_LIBRARIES})
|
||||
|
||||
if (CRYPTOPP_FOUND)
|
||||
TARGET_LINK_LIBRARIES(Test ${CRYPTOPP_LIBRARIES})
|
||||
endif()
|
||||
|
||||
enable_testing ()
|
||||
add_test(NAME ethash COMMAND Test)
|
||||
ENDIF()
|
||||
669
Godeps/_workspace/src/github.com/expanse-org/ethash/test/c/test.cpp
generated
vendored
669
Godeps/_workspace/src/github.com/expanse-org/ethash/test/c/test.cpp
generated
vendored
|
|
@ -1,669 +0,0 @@
|
|||
#include <iomanip>
|
||||
#include <libethash/fnv.h>
|
||||
#include <libethash/ethash.h>
|
||||
#include <libethash/internal.h>
|
||||
#include <libethash/io.h>
|
||||
|
||||
#ifdef WITH_CRYPTOPP
|
||||
|
||||
#include <libethash/sha3_cryptopp.h>
|
||||
|
||||
#else
|
||||
#include <libethash/sha3.h>
|
||||
#endif // WITH_CRYPTOPP
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <Shlobj.h>
|
||||
#endif
|
||||
|
||||
#define BOOST_TEST_MODULE Daggerhashimoto
|
||||
#define BOOST_TEST_MAIN
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace std;
|
||||
using byte = uint8_t;
|
||||
using bytes = std::vector<byte>;
|
||||
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__))
|
||||
|
||||
|
||||
// some functions taken from exp::dev for convenience.
|
||||
std::string bytesToHexString(const uint8_t *str, const uint64_t s)
|
||||
{
|
||||
std::ostringstream ret;
|
||||
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
ret << std::hex << std::setfill('0') << std::setw(2) << std::nouppercase << (int) str[i];
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
std::string blockhashToHexString(ethash_h256_t* _hash)
|
||||
{
|
||||
return bytesToHexString((uint8_t*)_hash, 32);
|
||||
}
|
||||
|
||||
int fromHex(char _i)
|
||||
{
|
||||
if (_i >= '0' && _i <= '9')
|
||||
return _i - '0';
|
||||
if (_i >= 'a' && _i <= 'f')
|
||||
return _i - 'a' + 10;
|
||||
if (_i >= 'A' && _i <= 'F')
|
||||
return _i - 'A' + 10;
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(false, "should never get here");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes hexStringToBytes(std::string const& _s)
|
||||
{
|
||||
unsigned s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0;
|
||||
std::vector<uint8_t> ret;
|
||||
ret.reserve((_s.size() - s + 1) / 2);
|
||||
|
||||
if (_s.size() % 2)
|
||||
try
|
||||
{
|
||||
ret.push_back(fromHex(_s[s++]));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ret.push_back(0);
|
||||
}
|
||||
for (unsigned i = s; i < _s.size(); i += 2)
|
||||
try
|
||||
{
|
||||
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
|
||||
}
|
||||
catch (...){
|
||||
ret.push_back(0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ethash_h256_t stringToBlockhash(std::string const& _s)
|
||||
{
|
||||
ethash_h256_t ret;
|
||||
bytes b = hexStringToBytes(_s);
|
||||
memcpy(&ret, b.data(), b.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fnv_hash_check) {
|
||||
uint32_t x = 1235U;
|
||||
const uint32_t
|
||||
y = 9999999U,
|
||||
expected = (FNV_PRIME * x) ^y;
|
||||
|
||||
x = fnv_hash(x, y);
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(x == expected,
|
||||
"\nexpected: " << expected << "\n"
|
||||
<< "actual: " << x << "\n");
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SHA256_check) {
|
||||
ethash_h256_t input;
|
||||
ethash_h256_t out;
|
||||
memcpy(&input, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
SHA3_256(&out, (uint8_t*)&input, 32);
|
||||
const std::string
|
||||
expected = "2b5ddf6f4d21c23de216f44d5e4bdc68e044b71897837ea74c83908be7037cd7",
|
||||
actual = bytesToHexString((uint8_t*)&out, 32);
|
||||
BOOST_REQUIRE_MESSAGE(expected == actual,
|
||||
"\nexpected: " << expected.c_str() << "\n"
|
||||
<< "actual: " << actual.c_str() << "\n");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SHA512_check) {
|
||||
uint8_t input[64], out[64];
|
||||
memcpy(input, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 64);
|
||||
SHA3_512(out, input, 64);
|
||||
const std::string
|
||||
expected = "0be8a1d334b4655fe58c6b38789f984bb13225684e86b20517a55ab2386c7b61c306f25e0627c60064cecd6d80cd67a82b3890bd1289b7ceb473aad56a359405",
|
||||
actual = bytesToHexString(out, 64);
|
||||
BOOST_REQUIRE_MESSAGE(expected == actual,
|
||||
"\nexpected: " << expected.c_str() << "\n"
|
||||
<< "actual: " << actual.c_str() << "\n");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_swap_endian32) {
|
||||
uint32_t v32 = (uint32_t)0xBAADF00D;
|
||||
v32 = ethash_swap_u32(v32);
|
||||
BOOST_REQUIRE_EQUAL(v32, (uint32_t)0x0DF0ADBA);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_swap_endian64) {
|
||||
uint64_t v64 = (uint64_t)0xFEE1DEADDEADBEEF;
|
||||
v64 = ethash_swap_u64(v64);
|
||||
BOOST_REQUIRE_EQUAL(v64, (uint64_t)0xEFBEADDEADDEE1FE);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) {
|
||||
uint64_t full_size = ethash_get_datasize(0);
|
||||
uint64_t cache_size = ethash_get_cachesize(0);
|
||||
BOOST_REQUIRE_MESSAGE(full_size < ETHASH_DATASET_BYTES_INIT,
|
||||
"\nfull size: " << full_size << "\n"
|
||||
<< "should be less than or equal to: " << ETHASH_DATASET_BYTES_INIT << "\n");
|
||||
BOOST_REQUIRE_MESSAGE(full_size + 20 * ETHASH_MIX_BYTES >= ETHASH_DATASET_BYTES_INIT,
|
||||
"\nfull size + 20*MIX_BYTES: " << full_size + 20 * ETHASH_MIX_BYTES << "\n"
|
||||
<< "should be greater than or equal to: " << ETHASH_DATASET_BYTES_INIT << "\n");
|
||||
BOOST_REQUIRE_MESSAGE(cache_size < ETHASH_DATASET_BYTES_INIT / 32,
|
||||
"\ncache size: " << cache_size << "\n"
|
||||
<< "should be less than or equal to: " << ETHASH_DATASET_BYTES_INIT / 32 << "\n");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) {
|
||||
uint64_t full_size = ethash_get_datasize(0);
|
||||
uint64_t cache_size = ethash_get_cachesize(0);
|
||||
const uint32_t expected_full_size = 1073739904;
|
||||
const uint32_t expected_cache_size = 16776896;
|
||||
BOOST_REQUIRE_MESSAGE(full_size == expected_full_size,
|
||||
"\nexpected: " << expected_cache_size << "\n"
|
||||
<< "actual: " << full_size << "\n");
|
||||
BOOST_REQUIRE_MESSAGE(cache_size == expected_cache_size,
|
||||
"\nexpected: " << expected_cache_size << "\n"
|
||||
<< "actual: " << cache_size << "\n");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ethash_check_difficulty_check) {
|
||||
ethash_h256_t hash;
|
||||
ethash_h256_t target;
|
||||
memcpy(&hash, "11111111111111111111111111111111", 32);
|
||||
memcpy(&target, "22222222222222222222222222222222", 32);
|
||||
BOOST_REQUIRE_MESSAGE(
|
||||
ethash_check_difficulty(&hash, &target),
|
||||
"\nexpected \"" << std::string((char *) &hash, 32).c_str() << "\" to have the same or less difficulty than \"" << std::string((char *) &target, 32).c_str() << "\"\n");
|
||||
BOOST_REQUIRE_MESSAGE(
|
||||
ethash_check_difficulty(&hash, &hash), "");
|
||||
// "\nexpected \"" << hash << "\" to have the same or less difficulty than \"" << hash << "\"\n");
|
||||
memcpy(&target, "11111111111111111111111111111112", 32);
|
||||
BOOST_REQUIRE_MESSAGE(
|
||||
ethash_check_difficulty(&hash, &target), "");
|
||||
// "\nexpected \"" << hash << "\" to have the same or less difficulty than \"" << target << "\"\n");
|
||||
memcpy(&target, "11111111111111111111111111111110", 32);
|
||||
BOOST_REQUIRE_MESSAGE(
|
||||
!ethash_check_difficulty(&hash, &target), "");
|
||||
// "\nexpected \"" << hash << "\" to have more difficulty than \"" << target << "\"\n");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ethash_io_mutable_name) {
|
||||
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
|
||||
// should have at least 8 bytes provided since this is what we test :)
|
||||
ethash_h256_t seed1 = ethash_h256_static_init(0, 10, 65, 255, 34, 55, 22, 8);
|
||||
ethash_io_mutable_name(1, &seed1, mutable_name);
|
||||
BOOST_REQUIRE_EQUAL(0, strcmp(mutable_name, "full-R1-000a41ff22371608"));
|
||||
ethash_h256_t seed2 = ethash_h256_static_init(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
ethash_io_mutable_name(44, &seed2, mutable_name);
|
||||
BOOST_REQUIRE_EQUAL(0, strcmp(mutable_name, "full-R44-0000000000000000"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ethash_dir_creation) {
|
||||
ethash_h256_t seedhash;
|
||||
FILE *f = NULL;
|
||||
memset(&seedhash, 0, 32);
|
||||
BOOST_REQUIRE_EQUAL(
|
||||
ETHASH_IO_MEMO_MISMATCH,
|
||||
ethash_io_prepare("./test_ethash_directory/", seedhash, &f, 64, false)
|
||||
);
|
||||
BOOST_REQUIRE(f);
|
||||
|
||||
// let's make sure that the directory was created
|
||||
BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/")));
|
||||
|
||||
// cleanup
|
||||
fclose(f);
|
||||
fs::remove_all("./test_ethash_directory/");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ethash_io_memo_file_match) {
|
||||
uint64_t full_size;
|
||||
uint64_t cache_size;
|
||||
ethash_h256_t seed;
|
||||
ethash_h256_t hash;
|
||||
FILE* f;
|
||||
memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
|
||||
cache_size = 1024;
|
||||
full_size = 1024 * 32;
|
||||
|
||||
ethash_light_t light = ethash_light_new_internal(cache_size, &seed);
|
||||
ethash_full_t full = ethash_full_new_internal(
|
||||
"./test_ethash_directory/",
|
||||
seed,
|
||||
full_size,
|
||||
light,
|
||||
NULL
|
||||
);
|
||||
BOOST_ASSERT(full);
|
||||
// let's make sure that the directory was created
|
||||
BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/")));
|
||||
// delete the full here so that memory is properly unmapped and FILE handler freed
|
||||
ethash_full_delete(full);
|
||||
// and check that we have a match when checking again
|
||||
BOOST_REQUIRE_EQUAL(
|
||||
ETHASH_IO_MEMO_MATCH,
|
||||
ethash_io_prepare("./test_ethash_directory/", seed, &f, full_size, false)
|
||||
);
|
||||
BOOST_REQUIRE(f);
|
||||
|
||||
// cleanup
|
||||
fclose(f);
|
||||
ethash_light_delete(light);
|
||||
fs::remove_all("./test_ethash_directory/");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ethash_io_memo_file_size_mismatch) {
|
||||
static const int blockn = 0;
|
||||
ethash_h256_t seedhash = ethash_get_seedhash(blockn);
|
||||
FILE *f = NULL;
|
||||
BOOST_REQUIRE_EQUAL(
|
||||
ETHASH_IO_MEMO_MISMATCH,
|
||||
ethash_io_prepare("./test_ethash_directory/", seedhash, &f, 64, false)
|
||||
);
|
||||
BOOST_REQUIRE(f);
|
||||
fclose(f);
|
||||
|
||||
// let's make sure that the directory was created
|
||||
BOOST_REQUIRE(fs::is_directory(fs::path("./test_ethash_directory/")));
|
||||
// and check that we get the size mismatch detected if we request diffferent size
|
||||
BOOST_REQUIRE_EQUAL(
|
||||
ETHASH_IO_MEMO_SIZE_MISMATCH,
|
||||
ethash_io_prepare("./test_ethash_directory/", seedhash, &f, 65, false)
|
||||
);
|
||||
|
||||
// cleanup
|
||||
fs::remove_all("./test_ethash_directory/");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ethash_get_default_dirname) {
|
||||
char result[256];
|
||||
// this is really not an easy thing to test for in a unit test
|
||||
// TODO: Improve this test ...
|
||||
#ifdef _WIN32
|
||||
char homedir[256];
|
||||
BOOST_REQUIRE(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, (CHAR*)homedir)));
|
||||
BOOST_REQUIRE(ethash_get_default_dirname(result, 256));
|
||||
std::string res = std::string(homedir) + std::string("\\AppData\\Local\\Ethash\\");
|
||||
#else
|
||||
char* homedir = getenv("HOME");
|
||||
BOOST_REQUIRE(ethash_get_default_dirname(result, 256));
|
||||
std::string res = std::string(homedir) + std::string("/.ethash/");
|
||||
#endif
|
||||
BOOST_CHECK_MESSAGE(strcmp(res.c_str(), result) == 0,
|
||||
"Expected \"" + res + "\" but got \"" + std::string(result) + "\""
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
|
||||
uint64_t full_size;
|
||||
uint64_t cache_size;
|
||||
ethash_h256_t seed;
|
||||
ethash_h256_t hash;
|
||||
ethash_h256_t difficulty;
|
||||
ethash_return_value_t light_out;
|
||||
ethash_return_value_t full_out;
|
||||
memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
|
||||
// Set the difficulty
|
||||
ethash_h256_set(&difficulty, 0, 197);
|
||||
ethash_h256_set(&difficulty, 1, 90);
|
||||
for (int i = 2; i < 32; i++)
|
||||
ethash_h256_set(&difficulty, i, 255);
|
||||
|
||||
cache_size = 1024;
|
||||
full_size = 1024 * 32;
|
||||
|
||||
ethash_light_t light = ethash_light_new_internal(cache_size, &seed);
|
||||
ethash_full_t full = ethash_full_new_internal(
|
||||
"./test_ethash_directory/",
|
||||
seed,
|
||||
full_size,
|
||||
light,
|
||||
NULL
|
||||
);
|
||||
BOOST_ASSERT(full);
|
||||
{
|
||||
const std::string
|
||||
expected = "2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b",
|
||||
actual = bytesToHexString((uint8_t const *) light->cache, cache_size);
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(expected == actual,
|
||||
"\nexpected: " << expected.c_str() << "\n"
|
||||
<< "actual: " << actual.c_str() << "\n");
|
||||
}
|
||||
{
|
||||
node node;
|
||||
ethash_calculate_dag_item(&node, 0, light);
|
||||
const std::string
|
||||
actual = bytesToHexString((uint8_t const *) &node, sizeof(node)),
|
||||
expected = "b1698f829f90b35455804e5185d78f549fcb1bdce2bee006d4d7e68eb154b596be1427769eb1c3c3e93180c760af75f81d1023da6a0ffbe321c153a7c0103597";
|
||||
BOOST_REQUIRE_MESSAGE(actual == expected,
|
||||
"\n" << "expected: " << expected.c_str() << "\n"
|
||||
<< "actual: " << actual.c_str() << "\n");
|
||||
}
|
||||
{
|
||||
for (int i = 0; i < full_size / sizeof(node); ++i) {
|
||||
for (uint32_t j = 0; j < 32; ++j) {
|
||||
node expected_node;
|
||||
ethash_calculate_dag_item(&expected_node, j, light);
|
||||
const std::string
|
||||
actual = bytesToHexString((uint8_t const *) &(full->data[j]), sizeof(node)),
|
||||
expected = bytesToHexString((uint8_t const *) &expected_node, sizeof(node));
|
||||
BOOST_REQUIRE_MESSAGE(actual == expected,
|
||||
"\ni: " << j << "\n"
|
||||
<< "expected: " << expected.c_str() << "\n"
|
||||
<< "actual: " << actual.c_str() << "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
uint64_t nonce = 0x7c7c597c;
|
||||
full_out = ethash_full_compute(full, hash, nonce);
|
||||
BOOST_REQUIRE(full_out.success);
|
||||
light_out = ethash_light_compute_internal(light, full_size, hash, nonce);
|
||||
BOOST_REQUIRE(light_out.success);
|
||||
const std::string
|
||||
light_result_string = blockhashToHexString(&light_out.result),
|
||||
full_result_string = blockhashToHexString(&full_out.result);
|
||||
BOOST_REQUIRE_MESSAGE(light_result_string == full_result_string,
|
||||
"\nlight result: " << light_result_string.c_str() << "\n"
|
||||
<< "full result: " << full_result_string.c_str() << "\n");
|
||||
const std::string
|
||||
light_mix_hash_string = blockhashToHexString(&light_out.mix_hash),
|
||||
full_mix_hash_string = blockhashToHexString(&full_out.mix_hash);
|
||||
BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string,
|
||||
"\nlight mix hash: " << light_mix_hash_string.c_str() << "\n"
|
||||
<< "full mix hash: " << full_mix_hash_string.c_str() << "\n");
|
||||
ethash_h256_t check_hash;
|
||||
ethash_quick_hash(&check_hash, &hash, nonce, &full_out.mix_hash);
|
||||
const std::string check_hash_string = blockhashToHexString(&check_hash);
|
||||
BOOST_REQUIRE_MESSAGE(check_hash_string == full_result_string,
|
||||
"\ncheck hash string: " << check_hash_string.c_str() << "\n"
|
||||
<< "full result: " << full_result_string.c_str() << "\n");
|
||||
}
|
||||
{
|
||||
full_out = ethash_full_compute(full, hash, 5);
|
||||
BOOST_REQUIRE(full_out.success);
|
||||
std::string
|
||||
light_result_string = blockhashToHexString(&light_out.result),
|
||||
full_result_string = blockhashToHexString(&full_out.result);
|
||||
BOOST_REQUIRE_MESSAGE(light_result_string != full_result_string,
|
||||
"\nlight result and full result should differ: " << light_result_string.c_str() << "\n");
|
||||
|
||||
light_out = ethash_light_compute_internal(light, full_size, hash, 5);
|
||||
BOOST_REQUIRE(light_out.success);
|
||||
light_result_string = blockhashToHexString(&light_out.result);
|
||||
BOOST_REQUIRE_MESSAGE(light_result_string == full_result_string,
|
||||
"\nlight result and full result should be the same\n"
|
||||
<< "light result: " << light_result_string.c_str() << "\n"
|
||||
<< "full result: " << full_result_string.c_str() << "\n");
|
||||
std::string
|
||||
light_mix_hash_string = blockhashToHexString(&light_out.mix_hash),
|
||||
full_mix_hash_string = blockhashToHexString(&full_out.mix_hash);
|
||||
BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string,
|
||||
"\nlight mix hash: " << light_mix_hash_string.c_str() << "\n"
|
||||
<< "full mix hash: " << full_mix_hash_string.c_str() << "\n");
|
||||
BOOST_REQUIRE_MESSAGE(ethash_check_difficulty(&full_out.result, &difficulty),
|
||||
"ethash_check_difficulty failed"
|
||||
);
|
||||
BOOST_REQUIRE_MESSAGE(ethash_quick_check_difficulty(&hash, 5U, &full_out.mix_hash, &difficulty),
|
||||
"ethash_quick_check_difficulty failed"
|
||||
);
|
||||
}
|
||||
ethash_light_delete(light);
|
||||
ethash_full_delete(full);
|
||||
fs::remove_all("./test_ethash_directory/");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ethash_full_new_when_dag_exists_with_wrong_size) {
|
||||
uint64_t full_size;
|
||||
uint64_t cache_size;
|
||||
ethash_h256_t seed;
|
||||
ethash_h256_t hash;
|
||||
ethash_return_value_t full_out;
|
||||
ethash_return_value_t light_out;
|
||||
memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
|
||||
cache_size = 1024;
|
||||
full_size = 1024 * 32;
|
||||
|
||||
// first make a DAG file of "wrong size"
|
||||
FILE *f;
|
||||
BOOST_REQUIRE_EQUAL(
|
||||
ETHASH_IO_MEMO_MISMATCH,
|
||||
ethash_io_prepare("./test_ethash_directory/", seed, &f, 64, false)
|
||||
);
|
||||
fclose(f);
|
||||
|
||||
// then create new DAG, which should detect the wrong size and force create a new file
|
||||
ethash_light_t light = ethash_light_new_internal(cache_size, &seed);
|
||||
BOOST_ASSERT(light);
|
||||
ethash_full_t full = ethash_full_new_internal(
|
||||
"./test_ethash_directory/",
|
||||
seed,
|
||||
full_size,
|
||||
light,
|
||||
NULL
|
||||
);
|
||||
BOOST_ASSERT(full);
|
||||
{
|
||||
uint64_t nonce = 0x7c7c597c;
|
||||
full_out = ethash_full_compute(full, hash, nonce);
|
||||
BOOST_REQUIRE(full_out.success);
|
||||
light_out = ethash_light_compute_internal(light, full_size, hash, nonce);
|
||||
BOOST_REQUIRE(light_out.success);
|
||||
const std::string
|
||||
light_result_string = blockhashToHexString(&light_out.result),
|
||||
full_result_string = blockhashToHexString(&full_out.result);
|
||||
BOOST_REQUIRE_MESSAGE(light_result_string == full_result_string,
|
||||
"\nlight result: " << light_result_string.c_str() << "\n"
|
||||
<< "full result: " << full_result_string.c_str() << "\n");
|
||||
const std::string
|
||||
light_mix_hash_string = blockhashToHexString(&light_out.mix_hash),
|
||||
full_mix_hash_string = blockhashToHexString(&full_out.mix_hash);
|
||||
BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string,
|
||||
"\nlight mix hash: " << light_mix_hash_string.c_str() << "\n"
|
||||
<< "full mix hash: " << full_mix_hash_string.c_str() << "\n");
|
||||
ethash_h256_t check_hash;
|
||||
ethash_quick_hash(&check_hash, &hash, nonce, &full_out.mix_hash);
|
||||
const std::string check_hash_string = blockhashToHexString(&check_hash);
|
||||
BOOST_REQUIRE_MESSAGE(check_hash_string == full_result_string,
|
||||
"\ncheck hash string: " << check_hash_string.c_str() << "\n"
|
||||
<< "full result: " << full_result_string.c_str() << "\n");
|
||||
}
|
||||
|
||||
ethash_light_delete(light);
|
||||
ethash_full_delete(full);
|
||||
fs::remove_all("./test_ethash_directory/");
|
||||
}
|
||||
|
||||
static bool g_executed = false;
|
||||
static unsigned g_prev_progress = 0;
|
||||
static int test_full_callback(unsigned _progress)
|
||||
{
|
||||
g_executed = true;
|
||||
BOOST_CHECK(_progress >= g_prev_progress);
|
||||
g_prev_progress = _progress;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_full_callback_that_fails(unsigned _progress)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_full_callback_create_incomplete_dag(unsigned _progress)
|
||||
{
|
||||
if (_progress >= 30) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(full_client_callback) {
|
||||
uint64_t full_size;
|
||||
uint64_t cache_size;
|
||||
ethash_h256_t seed;
|
||||
ethash_h256_t hash;
|
||||
memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
|
||||
cache_size = 1024;
|
||||
full_size = 1024 * 32;
|
||||
|
||||
ethash_light_t light = ethash_light_new_internal(cache_size, &seed);
|
||||
ethash_full_t full = ethash_full_new_internal(
|
||||
"./test_ethash_directory/",
|
||||
seed,
|
||||
full_size,
|
||||
light,
|
||||
test_full_callback
|
||||
);
|
||||
BOOST_ASSERT(full);
|
||||
BOOST_CHECK(g_executed);
|
||||
BOOST_REQUIRE_EQUAL(g_prev_progress, 100);
|
||||
|
||||
ethash_full_delete(full);
|
||||
ethash_light_delete(light);
|
||||
fs::remove_all("./test_ethash_directory/");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(failing_full_client_callback) {
|
||||
uint64_t full_size;
|
||||
uint64_t cache_size;
|
||||
ethash_h256_t seed;
|
||||
ethash_h256_t hash;
|
||||
memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
|
||||
cache_size = 1024;
|
||||
full_size = 1024 * 32;
|
||||
|
||||
ethash_light_t light = ethash_light_new_internal(cache_size, &seed);
|
||||
ethash_full_t full = ethash_full_new_internal(
|
||||
"./test_ethash_directory/",
|
||||
seed,
|
||||
full_size,
|
||||
light,
|
||||
test_full_callback_that_fails
|
||||
);
|
||||
BOOST_ASSERT(!full);
|
||||
ethash_light_delete(light);
|
||||
fs::remove_all("./test_ethash_directory/");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_incomplete_dag_file) {
|
||||
uint64_t full_size;
|
||||
uint64_t cache_size;
|
||||
ethash_h256_t seed;
|
||||
ethash_h256_t hash;
|
||||
memcpy(&seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
memcpy(&hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
|
||||
|
||||
cache_size = 1024;
|
||||
full_size = 1024 * 32;
|
||||
|
||||
ethash_light_t light = ethash_light_new_internal(cache_size, &seed);
|
||||
// create a full but stop at 30%, so no magic number is written
|
||||
ethash_full_t full = ethash_full_new_internal(
|
||||
"./test_ethash_directory/",
|
||||
seed,
|
||||
full_size,
|
||||
light,
|
||||
test_full_callback_create_incomplete_dag
|
||||
);
|
||||
BOOST_ASSERT(!full);
|
||||
FILE *f = NULL;
|
||||
// confirm that we get a size_mismatch because the magic number is missing
|
||||
BOOST_REQUIRE_EQUAL(
|
||||
ETHASH_IO_MEMO_SIZE_MISMATCH,
|
||||
ethash_io_prepare("./test_ethash_directory/", seed, &f, full_size, false)
|
||||
);
|
||||
ethash_light_delete(light);
|
||||
fs::remove_all("./test_ethash_directory/");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_block22_verification) {
|
||||
// from POC-9 testnet, epoch 0
|
||||
ethash_light_t light = ethash_light_new(22);
|
||||
ethash_h256_t seedhash = stringToBlockhash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d");
|
||||
BOOST_ASSERT(light);
|
||||
ethash_return_value_t ret = ethash_light_compute(
|
||||
light,
|
||||
seedhash,
|
||||
0x495732e0ed7a801cU
|
||||
);
|
||||
BOOST_REQUIRE_EQUAL(blockhashToHexString(&ret.result), "00000b184f1fdd88bfd94c86c39e65db0c36144d5e43f745f722196e730cb614");
|
||||
ethash_h256_t difficulty = ethash_h256_static_init(0x2, 0x5, 0x40);
|
||||
BOOST_REQUIRE(ethash_check_difficulty(&ret.result, &difficulty));
|
||||
ethash_light_delete(light);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_block30001_verification) {
|
||||
// from POC-9 testnet, epoch 1
|
||||
ethash_light_t light = ethash_light_new(30001);
|
||||
ethash_h256_t seedhash = stringToBlockhash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34");
|
||||
BOOST_ASSERT(light);
|
||||
ethash_return_value_t ret = ethash_light_compute(
|
||||
light,
|
||||
seedhash,
|
||||
0x318df1c8adef7e5eU
|
||||
);
|
||||
ethash_h256_t difficulty = ethash_h256_static_init(0x17, 0x62, 0xff);
|
||||
BOOST_REQUIRE(ethash_check_difficulty(&ret.result, &difficulty));
|
||||
ethash_light_delete(light);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_block60000_verification) {
|
||||
// from POC-9 testnet, epoch 2
|
||||
ethash_light_t light = ethash_light_new(60000);
|
||||
ethash_h256_t seedhash = stringToBlockhash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0");
|
||||
BOOST_ASSERT(light);
|
||||
ethash_return_value_t ret = ethash_light_compute(
|
||||
light,
|
||||
seedhash,
|
||||
0x50377003e5d830caU
|
||||
);
|
||||
ethash_h256_t difficulty = ethash_h256_static_init(0x25, 0xa6, 0x1e);
|
||||
BOOST_REQUIRE(ethash_check_difficulty(&ret.result, &difficulty));
|
||||
ethash_light_delete(light);
|
||||
}
|
||||
|
||||
// Test of Full DAG creation with the minimal ethash.h API.
|
||||
// Commented out since travis tests would take too much time.
|
||||
// Uncomment and run on your own machine if you want to confirm
|
||||
// it works fine.
|
||||
#if 0
|
||||
static int progress_cb(unsigned _progress)
|
||||
{
|
||||
printf("CREATING DAG. PROGRESS: %u\n", _progress);
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(full_dag_test) {
|
||||
ethash_light_t light = ethash_light_new(55);
|
||||
BOOST_ASSERT(light);
|
||||
ethash_full_t full = ethash_full_new(light, progress_cb);
|
||||
BOOST_ASSERT(full);
|
||||
ethash_light_delete(light);
|
||||
ethash_full_delete(full);
|
||||
}
|
||||
#endif
|
||||
32
Godeps/_workspace/src/github.com/expanse-org/ethash/test/c/test.sh
generated
vendored
32
Godeps/_workspace/src/github.com/expanse-org/ethash/test/c/test.sh
generated
vendored
|
|
@ -1,32 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Strict mode
|
||||
set -e
|
||||
|
||||
VALGRIND_ARGS="--tool=memcheck"
|
||||
VALGRIND_ARGS+=" --leak-check=yes"
|
||||
VALGRIND_ARGS+=" --track-origins=yes"
|
||||
VALGRIND_ARGS+=" --show-reachable=yes"
|
||||
VALGRIND_ARGS+=" --num-callers=20"
|
||||
VALGRIND_ARGS+=" --track-fds=yes"
|
||||
|
||||
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 )"
|
||||
|
||||
rm -rf $TEST_DIR/build
|
||||
mkdir -p $TEST_DIR/build
|
||||
cd $TEST_DIR/build ;
|
||||
cmake ../../.. > /dev/null
|
||||
make Test
|
||||
./test/c/Test
|
||||
|
||||
# If we have valgrind also run memory check tests
|
||||
if hash valgrind 2>/dev/null; then
|
||||
echo "======== Running tests under valgrind ========";
|
||||
cd $TEST_DIR/build/ && valgrind $VALGRIND_ARGS ./test/c/Test
|
||||
fi
|
||||
1
Godeps/_workspace/src/github.com/expanse-org/ethash/test/python/.gitignore
generated
vendored
1
Godeps/_workspace/src/github.com/expanse-org/ethash/test/python/.gitignore
generated
vendored
|
|
@ -1 +0,0 @@
|
|||
python-virtual-env/
|
||||
3
Godeps/_workspace/src/github.com/expanse-org/ethash/test/python/requirements.txt
generated
vendored
3
Godeps/_workspace/src/github.com/expanse-org/ethash/test/python/requirements.txt
generated
vendored
|
|
@ -1,3 +0,0 @@
|
|||
pyethereum==0.7.522
|
||||
nose==1.3.4
|
||||
pysha3==0.3
|
||||
30
Godeps/_workspace/src/github.com/expanse-org/ethash/test/python/test.sh
generated
vendored
30
Godeps/_workspace/src/github.com/expanse-org/ethash/test/python/test.sh
generated
vendored
|
|
@ -1,30 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Strict mode
|
||||
set -e
|
||||
|
||||
if [ -x "$(which virtualenv2)" ] ; then
|
||||
VIRTUALENV_EXEC=virtualenv2
|
||||
elif [ -x "$(which virtualenv)" ] ; then
|
||||
VIRTUALENV_EXEC=virtualenv
|
||||
else
|
||||
echo "Could not find a suitable version of virtualenv"
|
||||
false
|
||||
fi
|
||||
|
||||
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 )"
|
||||
|
||||
[ -d $TEST_DIR/python-virtual-env ] || $VIRTUALENV_EXEC --system-site-packages $TEST_DIR/python-virtual-env
|
||||
source $TEST_DIR/python-virtual-env/bin/activate
|
||||
pip install -r $TEST_DIR/requirements.txt > /dev/null
|
||||
# force installation of nose in virtualenv even if existing in thereuser's system
|
||||
pip install nose -I
|
||||
pip install --upgrade --no-deps --force-reinstall -e $TEST_DIR/../..
|
||||
cd $TEST_DIR
|
||||
nosetests --with-doctest -v --nocapture
|
||||
105
Godeps/_workspace/src/github.com/expanse-org/ethash/test/python/test_pyethash.py
generated
vendored
105
Godeps/_workspace/src/github.com/expanse-org/ethash/test/python/test_pyethash.py
generated
vendored
|
|
@ -1,105 +0,0 @@
|
|||
import pyethash
|
||||
from random import randint
|
||||
|
||||
def test_get_cache_size_not_None():
|
||||
for _ in range(100):
|
||||
block_num = randint(0,12456789)
|
||||
out = pyethash.get_cache_size(block_num)
|
||||
assert out != None
|
||||
|
||||
def test_get_full_size_not_None():
|
||||
for _ in range(100):
|
||||
block_num = randint(0,12456789)
|
||||
out = pyethash.get_full_size(block_num)
|
||||
assert out != None
|
||||
|
||||
def test_get_cache_size_based_on_EPOCH():
|
||||
for _ in range(100):
|
||||
block_num = randint(0,12456789)
|
||||
out1 = pyethash.get_cache_size(block_num)
|
||||
out2 = pyethash.get_cache_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
|
||||
assert out1 == out2
|
||||
|
||||
def test_get_full_size_based_on_EPOCH():
|
||||
for _ in range(100):
|
||||
block_num = randint(0,12456789)
|
||||
out1 = pyethash.get_full_size(block_num)
|
||||
out2 = pyethash.get_full_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
|
||||
assert out1 == out2
|
||||
|
||||
# See light_and_full_client_checks in test.cpp
|
||||
def test_mkcache_is_as_expected():
|
||||
actual = pyethash.mkcache_bytes(
|
||||
1024,
|
||||
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~").encode('hex')
|
||||
expected = "2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b"
|
||||
assert actual == expected
|
||||
|
||||
def test_calc_dataset_is_not_None():
|
||||
cache = pyethash.mkcache_bytes(
|
||||
1024,
|
||||
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||
assert pyethash.calc_dataset_bytes(1024 * 32, cache) != None
|
||||
|
||||
def test_light_and_full_agree():
|
||||
cache = pyethash.mkcache_bytes(
|
||||
1024,
|
||||
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||
full_size = 1024 * 32
|
||||
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
light_result = pyethash.hashimoto_light(full_size, cache, header, 0)
|
||||
dataset = pyethash.calc_dataset_bytes(full_size, cache)
|
||||
full_result = pyethash.hashimoto_full(dataset, header, 0)
|
||||
assert light_result["mix digest"] != None
|
||||
assert len(light_result["mix digest"]) == 32
|
||||
assert light_result["mix digest"] == full_result["mix digest"]
|
||||
assert light_result["result"] != None
|
||||
assert len(light_result["result"]) == 32
|
||||
assert light_result["result"] == full_result["result"]
|
||||
|
||||
def int_to_bytes(i):
|
||||
b = []
|
||||
for _ in range(32):
|
||||
b.append(chr(i & 0xff))
|
||||
i >>= 8
|
||||
b.reverse()
|
||||
return "".join(b)
|
||||
|
||||
def test_mining_basic():
|
||||
easy_difficulty = int_to_bytes(2**256 - 1)
|
||||
assert easy_difficulty.encode('hex') == 'f' * 64
|
||||
cache = pyethash.mkcache_bytes(
|
||||
1024,
|
||||
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||
full_size = 1024 * 32
|
||||
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
dataset = pyethash.calc_dataset_bytes(full_size, cache)
|
||||
# Check type of outputs
|
||||
assert type(pyethash.mine(dataset,header,easy_difficulty)) == dict
|
||||
assert type(pyethash.mine(dataset,header,easy_difficulty)["nonce"]) == long
|
||||
assert type(pyethash.mine(dataset,header,easy_difficulty)["mix digest"]) == str
|
||||
assert type(pyethash.mine(dataset,header,easy_difficulty)["result"]) == str
|
||||
|
||||
def test_mining_doesnt_always_return_the_same_value():
|
||||
easy_difficulty1 = int_to_bytes(int(2**256 * 0.999))
|
||||
# 1 in 1000 difficulty
|
||||
easy_difficulty2 = int_to_bytes(int(2**256 * 0.001))
|
||||
assert easy_difficulty1 != easy_difficulty2
|
||||
cache = pyethash.mkcache_bytes(
|
||||
1024,
|
||||
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||
full_size = 1024 * 32
|
||||
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
dataset = pyethash.calc_dataset_bytes(full_size, cache)
|
||||
# Check type of outputs
|
||||
assert pyethash.mine(dataset, header, easy_difficulty1)['nonce'] != pyethash.mine(dataset, header, easy_difficulty2)['nonce']
|
||||
|
||||
def test_get_seedhash():
|
||||
assert pyethash.get_seedhash(0).encode('hex') == '0' * 64
|
||||
import hashlib, sha3
|
||||
expected = pyethash.get_seedhash(0)
|
||||
#print "checking seed hashes:",
|
||||
for i in range(0, 30000*2048, 30000):
|
||||
#print i // 30000,
|
||||
assert pyethash.get_seedhash(i) == expected
|
||||
expected = hashlib.sha3_256(expected).digest()
|
||||
32
Godeps/_workspace/src/github.com/expanse-org/ethash/test/test.sh
generated
vendored
32
Godeps/_workspace/src/github.com/expanse-org/ethash/test/test.sh
generated
vendored
|
|
@ -1,32 +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 )"
|
||||
|
||||
echo -e "\n################# Testing JS ##################"
|
||||
# TODO: Use mocha and real testing tools instead of rolling our own
|
||||
cd $TEST_DIR/../js
|
||||
if [ -x "$(which nodejs)" ] ; then
|
||||
nodejs test.js
|
||||
fi
|
||||
if [ -x "$(which node)" ] ; then
|
||||
node test.js
|
||||
fi
|
||||
|
||||
echo -e "\n################# Testing C ##################"
|
||||
$TEST_DIR/c/test.sh
|
||||
|
||||
# Temporarily commenting out python tests until they conform to the API
|
||||
#echo -e "\n################# Testing Python ##################"
|
||||
#$TEST_DIR/python/test.sh
|
||||
|
||||
echo "################# Testing Go ##################"
|
||||
cd $TEST_DIR/.. && go test -timeout 9999s
|
||||
|
|
@ -26,7 +26,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
|
||||
)
|
||||
|
||||
// The ABI holds information about a contract's context and available
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package backends
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/expanse-org/go-expanse/accounts/abi/bind"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/core/types"
|
||||
)
|
||||
|
||||
// This nil assignment ensures compile time that nilBackend implements bind.ContractBackend.
|
||||
var _ bind.ContractBackend = (*nilBackend)(nil)
|
||||
|
||||
// nilBackend implements bind.ContractBackend, but panics on any method call.
|
||||
// Its sole purpose is to support the binding tests to construct the generated
|
||||
// wrappers without calling any methods on them.
|
||||
type nilBackend struct{}
|
||||
|
||||
func (*nilBackend) ContractCall(common.Address, []byte, bool) ([]byte, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
func (*nilBackend) EstimateGasLimit(common.Address, *common.Address, *big.Int, []byte) (*big.Int, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
func (*nilBackend) HasCode(common.Address, bool) (bool, error) { panic("not implemented") }
|
||||
func (*nilBackend) SuggestGasPrice() (*big.Int, error) { panic("not implemented") }
|
||||
func (*nilBackend) PendingAccountNonce(common.Address) (uint64, error) { panic("not implemented") }
|
||||
func (*nilBackend) SendTransaction(*types.Transaction) error { panic("not implemented") }
|
||||
|
||||
// NewNilBackend creates a new binding backend that can be used for instantiation
|
||||
// but will panic on any invocation. Its sole purpose is to help testing.
|
||||
func NewNilBackend() bind.ContractBackend {
|
||||
return new(nilBackend)
|
||||
}
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package backends
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/expanse-org/go-expanse/accounts/abi/bind"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/core/types"
|
||||
"github.com/expanse-org/go-expanse/rlp"
|
||||
"github.com/expanse-org/go-expanse/rpc"
|
||||
)
|
||||
|
||||
// This nil assignment ensures compile time that rpcBackend implements bind.ContractBackend.
|
||||
var _ bind.ContractBackend = (*rpcBackend)(nil)
|
||||
|
||||
// rpcBackend implements bind.ContractBackend, and acts as the data provider to
|
||||
// Expanse contracts bound to Go structs. It uses an RPC connection to delegate
|
||||
// all its functionality.
|
||||
//
|
||||
// Note: The current implementation is a blocking one. This should be replaced
|
||||
// by a proper async version when a real RPC client is created.
|
||||
type rpcBackend struct {
|
||||
client rpc.Client // RPC client connection to interact with an API server
|
||||
autoid uint32 // ID number to use for the next API request
|
||||
lock sync.Mutex // Singleton access until we get to request multiplexing
|
||||
}
|
||||
|
||||
// NewRPCBackend creates a new binding backend to an RPC provider that can be
|
||||
// used to interact with remote contracts.
|
||||
func NewRPCBackend(client rpc.Client) bind.ContractBackend {
|
||||
return &rpcBackend{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// request is a JSON RPC request package assembled internally from the client
|
||||
// method calls.
|
||||
type request struct {
|
||||
JSONRPC string `json:"jsonrpc"` // Version of the JSON RPC protocol, always set to 2.0
|
||||
ID int `json:"id"` // Auto incrementing ID number for this request
|
||||
Method string `json:"method"` // Remote procedure name to invoke on the server
|
||||
Params []interface{} `json:"params"` // List of parameters to pass through (keep types simple)
|
||||
}
|
||||
|
||||
// response is a JSON RPC response package sent back from the API server.
|
||||
type response struct {
|
||||
JSONRPC string `json:"jsonrpc"` // Version of the JSON RPC protocol, always set to 2.0
|
||||
ID int `json:"id"` // Auto incrementing ID number for this request
|
||||
Error *failure `json:"error"` // Any error returned by the remote side
|
||||
Result json.RawMessage `json:"result"` // Whatever the remote side sends us in reply
|
||||
}
|
||||
|
||||
// failure is a JSON RPC response error field sent back from the API server.
|
||||
type failure struct {
|
||||
Code int `json:"code"` // JSON RPC error code associated with the failure
|
||||
Message string `json:"message"` // Specific error message of the failure
|
||||
}
|
||||
|
||||
// request forwards an API request to the RPC server, and parses the response.
|
||||
//
|
||||
// This is currently painfully non-concurrent, but it will have to do until we
|
||||
// find the time for niceties like this :P
|
||||
func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessage, error) {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
// Ugly hack to serialize an empty list properly
|
||||
if params == nil {
|
||||
params = []interface{}{}
|
||||
}
|
||||
// Assemble the request object
|
||||
req := &request{
|
||||
JSONRPC: "2.0",
|
||||
ID: int(atomic.AddUint32(&b.autoid, 1)),
|
||||
Method: method,
|
||||
Params: params,
|
||||
}
|
||||
if err := b.client.Send(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := new(response)
|
||||
if err := b.client.Recv(res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.Error != nil {
|
||||
if res.Error.Message == bind.ErrNoCode.Error() {
|
||||
return nil, bind.ErrNoCode
|
||||
}
|
||||
return nil, fmt.Errorf("remote error: %s", res.Error.Message)
|
||||
}
|
||||
return res.Result, nil
|
||||
}
|
||||
|
||||
// HasCode implements ContractVerifier.HasCode by retrieving any code associated
|
||||
// with the contract from the remote node, and checking its size.
|
||||
func (b *rpcBackend) HasCode(contract common.Address, pending bool) (bool, error) {
|
||||
// Execute the RPC code retrieval
|
||||
block := "latest"
|
||||
if pending {
|
||||
block = "pending"
|
||||
}
|
||||
res, err := b.request("eth_getCode", []interface{}{contract.Hex(), block})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var hex string
|
||||
if err := json.Unmarshal(res, &hex); err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Convert the response back to a Go byte slice and return
|
||||
return len(common.FromHex(hex)) > 0, nil
|
||||
}
|
||||
|
||||
// ContractCall implements ContractCaller.ContractCall, delegating the execution of
|
||||
// a contract call to the remote node, returning the reply to for local processing.
|
||||
func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) {
|
||||
// Pack up the request into an RPC argument
|
||||
args := struct {
|
||||
To common.Address `json:"to"`
|
||||
Data string `json:"data"`
|
||||
}{
|
||||
To: contract,
|
||||
Data: common.ToHex(data),
|
||||
}
|
||||
// Execute the RPC call and retrieve the response
|
||||
block := "latest"
|
||||
if pending {
|
||||
block = "pending"
|
||||
}
|
||||
res, err := b.request("exp_call", []interface{}{args, block})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var hex string
|
||||
if err := json.Unmarshal(res, &hex); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Convert the response back to a Go byte slice and return
|
||||
return common.FromHex(hex), nil
|
||||
}
|
||||
|
||||
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, delegating
|
||||
// the current account nonce retrieval to the remote node.
|
||||
func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error) {
|
||||
res, err := b.request("exp_getTransactionCount", []interface{}{account.Hex(), "pending"})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var hex string
|
||||
if err := json.Unmarshal(res, &hex); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
nonce, ok := new(big.Int).SetString(hex, 0)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("invalid nonce hex: %s", hex)
|
||||
}
|
||||
return nonce.Uint64(), nil
|
||||
}
|
||||
|
||||
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice, delegating the
|
||||
// gas price oracle request to the remote node.
|
||||
func (b *rpcBackend) SuggestGasPrice() (*big.Int, error) {
|
||||
res, err := b.request("exp_gasPrice", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var hex string
|
||||
if err := json.Unmarshal(res, &hex); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
price, ok := new(big.Int).SetString(hex, 0)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid price hex: %s", hex)
|
||||
}
|
||||
return price, nil
|
||||
}
|
||||
|
||||
// EstimateGasLimit implements ContractTransactor.EstimateGasLimit, delegating
|
||||
// the gas estimation to the remote node.
|
||||
func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
|
||||
// Pack up the request into an RPC argument
|
||||
args := struct {
|
||||
From common.Address `json:"from"`
|
||||
To *common.Address `json:"to"`
|
||||
Value *rpc.HexNumber `json:"value"`
|
||||
Data string `json:"data"`
|
||||
}{
|
||||
From: sender,
|
||||
To: contract,
|
||||
Data: common.ToHex(data),
|
||||
Value: rpc.NewHexNumber(value),
|
||||
}
|
||||
// Execute the RPC call and retrieve the response
|
||||
res, err := b.request("exp_estimateGas", []interface{}{args})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var hex string
|
||||
if err := json.Unmarshal(res, &hex); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
estimate, ok := new(big.Int).SetString(hex, 0)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid estimate hex: %s", hex)
|
||||
}
|
||||
return estimate, nil
|
||||
}
|
||||
|
||||
// SendTransaction implements ContractTransactor.SendTransaction, delegating the
|
||||
// raw transaction injection to the remote node.
|
||||
func (b *rpcBackend) SendTransaction(tx *types.Transaction) error {
|
||||
data, err := rlp.EncodeToBytes(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res, err := b.request("exp_sendRawTransaction", []interface{}{common.ToHex(data)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var hex string
|
||||
if err := json.Unmarshal(res, &hex); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,342 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Package accounts implements encrypted storage of secp256k1 private keys.
|
||||
//
|
||||
// Keys are stored as encrypted JSON files according to the Web3 Secret Storage specification.
|
||||
// See https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition for more information.
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
crand "crypto/rand"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLocked = errors.New("account is locked")
|
||||
ErrNoMatch = errors.New("no key for given address or file")
|
||||
ErrDecrypt = errors.New("could not decrypt key with given passphrase")
|
||||
)
|
||||
|
||||
// Account represents a stored key.
|
||||
// When used as an argument, it selects a unique key file to act on.
|
||||
type Account struct {
|
||||
Address common.Address // Expanse account address derived from the key
|
||||
|
||||
// File contains the key file name.
|
||||
// When Acccount is used as an argument to select a key, File can be left blank to
|
||||
// select just by address or set to the basename or absolute path of a file in the key
|
||||
// directory. Accounts returned by Manager will always contain an absolute path.
|
||||
File string
|
||||
}
|
||||
|
||||
func (acc *Account) MarshalJSON() ([]byte, error) {
|
||||
return []byte(`"` + acc.Address.Hex() + `"`), nil
|
||||
}
|
||||
|
||||
func (acc *Account) UnmarshalJSON(raw []byte) error {
|
||||
return json.Unmarshal(raw, &acc.Address)
|
||||
}
|
||||
|
||||
// Manager manages a key storage directory on disk.
|
||||
type Manager struct {
|
||||
cache *addrCache
|
||||
keyStore keyStore
|
||||
mu sync.RWMutex
|
||||
unlocked map[common.Address]*unlocked
|
||||
}
|
||||
|
||||
type unlocked struct {
|
||||
*Key
|
||||
abort chan struct{}
|
||||
}
|
||||
|
||||
// NewManager creates a manager for the given directory.
|
||||
func NewManager(keydir string, scryptN, scryptP int) *Manager {
|
||||
keydir, _ = filepath.Abs(keydir)
|
||||
am := &Manager{keyStore: &keyStorePassphrase{keydir, scryptN, scryptP}}
|
||||
am.init(keydir)
|
||||
return am
|
||||
}
|
||||
|
||||
// NewPlaintextManager creates a manager for the given directory.
|
||||
// Deprecated: Use NewManager.
|
||||
func NewPlaintextManager(keydir string) *Manager {
|
||||
keydir, _ = filepath.Abs(keydir)
|
||||
am := &Manager{keyStore: &keyStorePlain{keydir}}
|
||||
am.init(keydir)
|
||||
return am
|
||||
}
|
||||
|
||||
func (am *Manager) init(keydir string) {
|
||||
am.unlocked = make(map[common.Address]*unlocked)
|
||||
am.cache = newAddrCache(keydir)
|
||||
// TODO: In order for this finalizer to work, there must be no references
|
||||
// to am. addrCache doesn't keep a reference but unlocked keys do,
|
||||
// so the finalizer will not trigger until all timed unlocks have expired.
|
||||
runtime.SetFinalizer(am, func(m *Manager) {
|
||||
m.cache.close()
|
||||
})
|
||||
}
|
||||
|
||||
// HasAddress reports whether a key with the given address is present.
|
||||
func (am *Manager) HasAddress(addr common.Address) bool {
|
||||
return am.cache.hasAddress(addr)
|
||||
}
|
||||
|
||||
// Accounts returns all key files present in the directory.
|
||||
func (am *Manager) Accounts() []Account {
|
||||
return am.cache.accounts()
|
||||
}
|
||||
|
||||
// DeleteAccount deletes the key matched by account if the passphrase is correct.
|
||||
// If a contains no filename, the address must match a unique key.
|
||||
func (am *Manager) DeleteAccount(a Account, passphrase string) error {
|
||||
// Decrypting the key isn't really necessary, but we do
|
||||
// it anyway to check the password and zero out the key
|
||||
// immediately afterwards.
|
||||
a, key, err := am.getDecryptedKey(a, passphrase)
|
||||
if key != nil {
|
||||
zeroKey(key.PrivateKey)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// The order is crucial here. The key is dropped from the
|
||||
// cache after the file is gone so that a reload happening in
|
||||
// between won't insert it into the cache again.
|
||||
err = os.Remove(a.File)
|
||||
if err == nil {
|
||||
am.cache.delete(a)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Sign signs hash with an unlocked private key matching the given address.
|
||||
func (am *Manager) Sign(addr common.Address, hash []byte) (signature []byte, err error) {
|
||||
am.mu.RLock()
|
||||
defer am.mu.RUnlock()
|
||||
unlockedKey, found := am.unlocked[addr]
|
||||
if !found {
|
||||
return nil, ErrLocked
|
||||
}
|
||||
return crypto.Sign(hash, unlockedKey.PrivateKey)
|
||||
}
|
||||
|
||||
// SignWithPassphrase signs hash if the private key matching the given address can be
|
||||
// decrypted with the given passphrase.
|
||||
func (am *Manager) SignWithPassphrase(addr common.Address, passphrase string, hash []byte) (signature []byte, err error) {
|
||||
_, key, err := am.getDecryptedKey(Account{Address: addr}, passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer zeroKey(key.PrivateKey)
|
||||
return crypto.Sign(hash, key.PrivateKey)
|
||||
}
|
||||
|
||||
// Unlock unlocks the given account indefinitely.
|
||||
func (am *Manager) Unlock(a Account, passphrase string) error {
|
||||
return am.TimedUnlock(a, passphrase, 0)
|
||||
}
|
||||
|
||||
// Lock removes the private key with the given address from memory.
|
||||
func (am *Manager) Lock(addr common.Address) error {
|
||||
am.mu.Lock()
|
||||
if unl, found := am.unlocked[addr]; found {
|
||||
am.mu.Unlock()
|
||||
am.expire(addr, unl, time.Duration(0)*time.Nanosecond)
|
||||
} else {
|
||||
am.mu.Unlock()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TimedUnlock unlocks the given account with the passphrase. The account
|
||||
// stays unlocked for the duration of timeout. A timeout of 0 unlocks the account
|
||||
// until the program exits. The account must match a unique key file.
|
||||
//
|
||||
// If the account address is already unlocked for a duration, TimedUnlock extends or
|
||||
// shortens the active unlock timeout. If the address was previously unlocked
|
||||
// indefinitely the timeout is not altered.
|
||||
func (am *Manager) TimedUnlock(a Account, passphrase string, timeout time.Duration) error {
|
||||
a, key, err := am.getDecryptedKey(a, passphrase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
am.mu.Lock()
|
||||
defer am.mu.Unlock()
|
||||
u, found := am.unlocked[a.Address]
|
||||
if found {
|
||||
if u.abort == nil {
|
||||
// The address was unlocked indefinitely, so unlocking
|
||||
// it with a timeout would be confusing.
|
||||
zeroKey(key.PrivateKey)
|
||||
return nil
|
||||
} else {
|
||||
// Terminate the expire goroutine and replace it below.
|
||||
close(u.abort)
|
||||
}
|
||||
}
|
||||
if timeout > 0 {
|
||||
u = &unlocked{Key: key, abort: make(chan struct{})}
|
||||
go am.expire(a.Address, u, timeout)
|
||||
} else {
|
||||
u = &unlocked{Key: key}
|
||||
}
|
||||
am.unlocked[a.Address] = u
|
||||
return nil
|
||||
}
|
||||
|
||||
func (am *Manager) getDecryptedKey(a Account, auth string) (Account, *Key, error) {
|
||||
am.cache.maybeReload()
|
||||
am.cache.mu.Lock()
|
||||
a, err := am.cache.find(a)
|
||||
am.cache.mu.Unlock()
|
||||
if err != nil {
|
||||
return a, nil, err
|
||||
}
|
||||
key, err := am.keyStore.GetKey(a.Address, a.File, auth)
|
||||
return a, key, err
|
||||
}
|
||||
|
||||
func (am *Manager) expire(addr common.Address, u *unlocked, timeout time.Duration) {
|
||||
t := time.NewTimer(timeout)
|
||||
defer t.Stop()
|
||||
select {
|
||||
case <-u.abort:
|
||||
// just quit
|
||||
case <-t.C:
|
||||
am.mu.Lock()
|
||||
// only drop if it's still the same key instance that dropLater
|
||||
// was launched with. we can check that using pointer equality
|
||||
// because the map stores a new pointer every time the key is
|
||||
// unlocked.
|
||||
if am.unlocked[addr] == u {
|
||||
zeroKey(u.PrivateKey)
|
||||
delete(am.unlocked, addr)
|
||||
}
|
||||
am.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// NewAccount generates a new key and stores it into the key directory,
|
||||
// encrypting it with the passphrase.
|
||||
func (am *Manager) NewAccount(passphrase string) (Account, error) {
|
||||
_, account, err := storeNewKey(am.keyStore, crand.Reader, passphrase)
|
||||
if err != nil {
|
||||
return Account{}, err
|
||||
}
|
||||
// Add the account to the cache immediately rather
|
||||
// than waiting for file system notifications to pick it up.
|
||||
am.cache.add(account)
|
||||
return account, nil
|
||||
}
|
||||
|
||||
// AccountByIndex returns the ith account.
|
||||
func (am *Manager) AccountByIndex(i int) (Account, error) {
|
||||
accounts := am.Accounts()
|
||||
if i < 0 || i >= len(accounts) {
|
||||
return Account{}, fmt.Errorf("account index %d out of range [0, %d]", i, len(accounts)-1)
|
||||
}
|
||||
return accounts[i], nil
|
||||
}
|
||||
|
||||
// Export exports as a JSON key, encrypted with newPassphrase.
|
||||
func (am *Manager) Export(a Account, passphrase, newPassphrase string) (keyJSON []byte, err error) {
|
||||
_, key, err := am.getDecryptedKey(a, passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var N, P int
|
||||
if store, ok := am.keyStore.(*keyStorePassphrase); ok {
|
||||
N, P = store.scryptN, store.scryptP
|
||||
} else {
|
||||
N, P = StandardScryptN, StandardScryptP
|
||||
}
|
||||
return EncryptKey(key, newPassphrase, N, P)
|
||||
}
|
||||
|
||||
// Import stores the given encrypted JSON key into the key directory.
|
||||
func (am *Manager) Import(keyJSON []byte, passphrase, newPassphrase string) (Account, error) {
|
||||
key, err := DecryptKey(keyJSON, passphrase)
|
||||
if key != nil && key.PrivateKey != nil {
|
||||
defer zeroKey(key.PrivateKey)
|
||||
}
|
||||
if err != nil {
|
||||
return Account{}, err
|
||||
}
|
||||
return am.importKey(key, newPassphrase)
|
||||
}
|
||||
|
||||
// ImportECDSA stores the given key into the key directory, encrypting it with the passphrase.
|
||||
func (am *Manager) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (Account, error) {
|
||||
key := newKeyFromECDSA(priv)
|
||||
if am.cache.hasAddress(key.Address) {
|
||||
return Account{}, fmt.Errorf("account already exists")
|
||||
}
|
||||
|
||||
return am.importKey(key, passphrase)
|
||||
}
|
||||
|
||||
func (am *Manager) importKey(key *Key, passphrase string) (Account, error) {
|
||||
a := Account{Address: key.Address, File: am.keyStore.JoinPath(keyFileName(key.Address))}
|
||||
if err := am.keyStore.StoreKey(a.File, key, passphrase); err != nil {
|
||||
return Account{}, err
|
||||
}
|
||||
am.cache.add(a)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Update changes the passphrase of an existing account.
|
||||
func (am *Manager) Update(a Account, passphrase, newPassphrase string) error {
|
||||
a, key, err := am.getDecryptedKey(a, passphrase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return am.keyStore.StoreKey(a.File, key, newPassphrase)
|
||||
}
|
||||
|
||||
// ImportPreSaleKey decrypts the given Expanse presale wallet and stores
|
||||
// a key file in the key directory. The key file is encrypted with the same passphrase.
|
||||
func (am *Manager) ImportPreSaleKey(keyJSON []byte, passphrase string) (Account, error) {
|
||||
a, _, err := importPreSaleKey(am.keyStore, keyJSON, passphrase)
|
||||
if err != nil {
|
||||
return a, err
|
||||
}
|
||||
am.cache.add(a)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// zeroKey zeroes a private key in memory.
|
||||
func zeroKey(k *ecdsa.PrivateKey) {
|
||||
b := k.D.Bits()
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -1,269 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/logger"
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
)
|
||||
|
||||
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
||||
// not support change notifications. It also applies if the keystore directory does not
|
||||
// exist yet, the code will attempt to create a watcher at most this often.
|
||||
const minReloadInterval = 2 * time.Second
|
||||
|
||||
type accountsByFile []Account
|
||||
|
||||
func (s accountsByFile) Len() int { return len(s) }
|
||||
func (s accountsByFile) Less(i, j int) bool { return s[i].File < s[j].File }
|
||||
func (s accountsByFile) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// AmbiguousAddrError is returned when attempting to unlock
|
||||
// an address for which more than one file exists.
|
||||
type AmbiguousAddrError struct {
|
||||
Addr common.Address
|
||||
Matches []Account
|
||||
}
|
||||
|
||||
func (err *AmbiguousAddrError) Error() string {
|
||||
files := ""
|
||||
for i, a := range err.Matches {
|
||||
files += a.File
|
||||
if i < len(err.Matches)-1 {
|
||||
files += ", "
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("multiple keys match address (%s)", files)
|
||||
}
|
||||
|
||||
// addrCache is a live index of all accounts in the keystore.
|
||||
type addrCache struct {
|
||||
keydir string
|
||||
watcher *watcher
|
||||
mu sync.Mutex
|
||||
all accountsByFile
|
||||
byAddr map[common.Address][]Account
|
||||
throttle *time.Timer
|
||||
}
|
||||
|
||||
func newAddrCache(keydir string) *addrCache {
|
||||
ac := &addrCache{
|
||||
keydir: keydir,
|
||||
byAddr: make(map[common.Address][]Account),
|
||||
}
|
||||
ac.watcher = newWatcher(ac)
|
||||
return ac
|
||||
}
|
||||
|
||||
func (ac *addrCache) accounts() []Account {
|
||||
ac.maybeReload()
|
||||
ac.mu.Lock()
|
||||
defer ac.mu.Unlock()
|
||||
cpy := make([]Account, len(ac.all))
|
||||
copy(cpy, ac.all)
|
||||
return cpy
|
||||
}
|
||||
|
||||
func (ac *addrCache) hasAddress(addr common.Address) bool {
|
||||
ac.maybeReload()
|
||||
ac.mu.Lock()
|
||||
defer ac.mu.Unlock()
|
||||
return len(ac.byAddr[addr]) > 0
|
||||
}
|
||||
|
||||
func (ac *addrCache) add(newAccount Account) {
|
||||
ac.mu.Lock()
|
||||
defer ac.mu.Unlock()
|
||||
|
||||
i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].File >= newAccount.File })
|
||||
if i < len(ac.all) && ac.all[i] == newAccount {
|
||||
return
|
||||
}
|
||||
// newAccount is not in the cache.
|
||||
ac.all = append(ac.all, Account{})
|
||||
copy(ac.all[i+1:], ac.all[i:])
|
||||
ac.all[i] = newAccount
|
||||
ac.byAddr[newAccount.Address] = append(ac.byAddr[newAccount.Address], newAccount)
|
||||
}
|
||||
|
||||
// note: removed needs to be unique here (i.e. both File and Address must be set).
|
||||
func (ac *addrCache) delete(removed Account) {
|
||||
ac.mu.Lock()
|
||||
defer ac.mu.Unlock()
|
||||
ac.all = removeAccount(ac.all, removed)
|
||||
if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 {
|
||||
delete(ac.byAddr, removed.Address)
|
||||
} else {
|
||||
ac.byAddr[removed.Address] = ba
|
||||
}
|
||||
}
|
||||
|
||||
func removeAccount(slice []Account, elem Account) []Account {
|
||||
for i := range slice {
|
||||
if slice[i] == elem {
|
||||
return append(slice[:i], slice[i+1:]...)
|
||||
}
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
// find returns the cached account for address if there is a unique match.
|
||||
// The exact matching rules are explained by the documentation of Account.
|
||||
// Callers must hold ac.mu.
|
||||
func (ac *addrCache) find(a Account) (Account, error) {
|
||||
// Limit search to address candidates if possible.
|
||||
matches := ac.all
|
||||
if (a.Address != common.Address{}) {
|
||||
matches = ac.byAddr[a.Address]
|
||||
}
|
||||
if a.File != "" {
|
||||
// If only the basename is specified, complete the path.
|
||||
if !strings.ContainsRune(a.File, filepath.Separator) {
|
||||
a.File = filepath.Join(ac.keydir, a.File)
|
||||
}
|
||||
for i := range matches {
|
||||
if matches[i].File == a.File {
|
||||
return matches[i], nil
|
||||
}
|
||||
}
|
||||
if (a.Address == common.Address{}) {
|
||||
return Account{}, ErrNoMatch
|
||||
}
|
||||
}
|
||||
switch len(matches) {
|
||||
case 1:
|
||||
return matches[0], nil
|
||||
case 0:
|
||||
return Account{}, ErrNoMatch
|
||||
default:
|
||||
err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]Account, len(matches))}
|
||||
copy(err.Matches, matches)
|
||||
return Account{}, err
|
||||
}
|
||||
}
|
||||
|
||||
func (ac *addrCache) maybeReload() {
|
||||
ac.mu.Lock()
|
||||
defer ac.mu.Unlock()
|
||||
if ac.watcher.running {
|
||||
return // A watcher is running and will keep the cache up-to-date.
|
||||
}
|
||||
if ac.throttle == nil {
|
||||
ac.throttle = time.NewTimer(0)
|
||||
} else {
|
||||
select {
|
||||
case <-ac.throttle.C:
|
||||
default:
|
||||
return // The cache was reloaded recently.
|
||||
}
|
||||
}
|
||||
ac.watcher.start()
|
||||
ac.reload()
|
||||
ac.throttle.Reset(minReloadInterval)
|
||||
}
|
||||
|
||||
func (ac *addrCache) close() {
|
||||
ac.mu.Lock()
|
||||
ac.watcher.close()
|
||||
if ac.throttle != nil {
|
||||
ac.throttle.Stop()
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
}
|
||||
|
||||
// reload caches addresses of existing accounts.
|
||||
// Callers must hold ac.mu.
|
||||
func (ac *addrCache) reload() {
|
||||
accounts, err := ac.scan()
|
||||
if err != nil && glog.V(logger.Debug) {
|
||||
glog.Errorf("can't load keys: %v", err)
|
||||
}
|
||||
ac.all = accounts
|
||||
sort.Sort(ac.all)
|
||||
for k := range ac.byAddr {
|
||||
delete(ac.byAddr, k)
|
||||
}
|
||||
for _, a := range accounts {
|
||||
ac.byAddr[a.Address] = append(ac.byAddr[a.Address], a)
|
||||
}
|
||||
glog.V(logger.Debug).Infof("reloaded keys, cache has %d accounts", len(ac.all))
|
||||
}
|
||||
|
||||
func (ac *addrCache) scan() ([]Account, error) {
|
||||
files, err := ioutil.ReadDir(ac.keydir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
buf = new(bufio.Reader)
|
||||
addrs []Account
|
||||
keyJSON struct {
|
||||
Address common.Address `json:"address"`
|
||||
}
|
||||
)
|
||||
for _, fi := range files {
|
||||
path := filepath.Join(ac.keydir, fi.Name())
|
||||
if skipKeyFile(fi) {
|
||||
glog.V(logger.Detail).Infof("ignoring file %s", path)
|
||||
continue
|
||||
}
|
||||
fd, err := os.Open(path)
|
||||
if err != nil {
|
||||
glog.V(logger.Detail).Infoln(err)
|
||||
continue
|
||||
}
|
||||
buf.Reset(fd)
|
||||
// Parse the address.
|
||||
keyJSON.Address = common.Address{}
|
||||
err = json.NewDecoder(buf).Decode(&keyJSON)
|
||||
switch {
|
||||
case err != nil:
|
||||
glog.V(logger.Debug).Infof("can't decode key %s: %v", path, err)
|
||||
case (keyJSON.Address == common.Address{}):
|
||||
glog.V(logger.Debug).Infof("can't decode key %s: missing or zero address", path)
|
||||
default:
|
||||
addrs = append(addrs, Account{Address: keyJSON.Address, File: path})
|
||||
}
|
||||
fd.Close()
|
||||
}
|
||||
return addrs, err
|
||||
}
|
||||
|
||||
func skipKeyFile(fi os.FileInfo) bool {
|
||||
// Skip editor backups and UNIX-style hidden files.
|
||||
if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") {
|
||||
return true
|
||||
}
|
||||
// Skip misc special files, directories (yes, symlinks too).
|
||||
if fi.IsDir() || fi.Mode()&os.ModeType != 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cespare/cp"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
)
|
||||
|
||||
var (
|
||||
cachetestDir, _ = filepath.Abs(filepath.Join("testdata", "keystore"))
|
||||
cachetestAccounts = []Account{
|
||||
{
|
||||
Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
|
||||
File: filepath.Join(cachetestDir, "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
|
||||
File: filepath.Join(cachetestDir, "aaa"),
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
|
||||
File: filepath.Join(cachetestDir, "zzz"),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestWatchNewFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir, am := tmpManager(t, false)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// Ensure the watcher is started before adding any files.
|
||||
am.Accounts()
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
// Move in the files.
|
||||
wantAccounts := make([]Account, len(cachetestAccounts))
|
||||
for i := range cachetestAccounts {
|
||||
a := cachetestAccounts[i]
|
||||
a.File = filepath.Join(dir, filepath.Base(a.File))
|
||||
wantAccounts[i] = a
|
||||
if err := cp.CopyFile(a.File, cachetestAccounts[i].File); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// am should see the accounts.
|
||||
var list []Account
|
||||
for d := 200 * time.Millisecond; d < 5*time.Second; d *= 2 {
|
||||
list = am.Accounts()
|
||||
if reflect.DeepEqual(list, wantAccounts) {
|
||||
return
|
||||
}
|
||||
time.Sleep(d)
|
||||
}
|
||||
t.Errorf("got %s, want %s", spew.Sdump(list), spew.Sdump(wantAccounts))
|
||||
}
|
||||
|
||||
func TestWatchNoDir(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create am but not the directory that it watches.
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watch-test-%d-%d", os.Getpid(), rand.Int()))
|
||||
am := NewManager(dir, LightScryptN, LightScryptP)
|
||||
|
||||
list := am.Accounts()
|
||||
if len(list) > 0 {
|
||||
t.Error("initial account list not empty:", list)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Create the directory and copy a key file into it.
|
||||
os.MkdirAll(dir, 0700)
|
||||
defer os.RemoveAll(dir)
|
||||
file := filepath.Join(dir, "aaa")
|
||||
if err := cp.CopyFile(file, cachetestAccounts[0].File); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// am should see the account.
|
||||
wantAccounts := []Account{cachetestAccounts[0]}
|
||||
wantAccounts[0].File = file
|
||||
for d := 200 * time.Millisecond; d < 8*time.Second; d *= 2 {
|
||||
list = am.Accounts()
|
||||
if reflect.DeepEqual(list, wantAccounts) {
|
||||
return
|
||||
}
|
||||
time.Sleep(d)
|
||||
}
|
||||
t.Errorf("\ngot %v\nwant %v", list, wantAccounts)
|
||||
}
|
||||
|
||||
func TestCacheInitialReload(t *testing.T) {
|
||||
cache := newAddrCache(cachetestDir)
|
||||
accounts := cache.accounts()
|
||||
if !reflect.DeepEqual(accounts, cachetestAccounts) {
|
||||
t.Fatalf("got initial accounts: %swant %s", spew.Sdump(accounts), spew.Sdump(cachetestAccounts))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheAddDeleteOrder(t *testing.T) {
|
||||
cache := newAddrCache("testdata/no-such-dir")
|
||||
cache.watcher.running = true // prevent unexpected reloads
|
||||
|
||||
accounts := []Account{
|
||||
{
|
||||
Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
|
||||
File: "-309830980",
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
|
||||
File: "ggg",
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"),
|
||||
File: "zzzzzz-the-very-last-one.keyXXX",
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
|
||||
File: "SOMETHING.key",
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
|
||||
File: "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
|
||||
File: "aaa",
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
|
||||
File: "zzz",
|
||||
},
|
||||
}
|
||||
for _, a := range accounts {
|
||||
cache.add(a)
|
||||
}
|
||||
// Add some of them twice to check that they don't get reinserted.
|
||||
cache.add(accounts[0])
|
||||
cache.add(accounts[2])
|
||||
|
||||
// Check that the account list is sorted by filename.
|
||||
wantAccounts := make([]Account, len(accounts))
|
||||
copy(wantAccounts, accounts)
|
||||
sort.Sort(accountsByFile(wantAccounts))
|
||||
list := cache.accounts()
|
||||
if !reflect.DeepEqual(list, wantAccounts) {
|
||||
t.Fatalf("got accounts: %s\nwant %s", spew.Sdump(accounts), spew.Sdump(wantAccounts))
|
||||
}
|
||||
for _, a := range accounts {
|
||||
if !cache.hasAddress(a.Address) {
|
||||
t.Errorf("expected hasAccount(%x) to return true", a.Address)
|
||||
}
|
||||
}
|
||||
if cache.hasAddress(common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e")) {
|
||||
t.Errorf("expected hasAccount(%x) to return false", common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"))
|
||||
}
|
||||
|
||||
// Delete a few keys from the cache.
|
||||
for i := 0; i < len(accounts); i += 2 {
|
||||
cache.delete(wantAccounts[i])
|
||||
}
|
||||
cache.delete(Account{Address: common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"), File: "something"})
|
||||
|
||||
// Check content again after deletion.
|
||||
wantAccountsAfterDelete := []Account{
|
||||
wantAccounts[1],
|
||||
wantAccounts[3],
|
||||
wantAccounts[5],
|
||||
}
|
||||
list = cache.accounts()
|
||||
if !reflect.DeepEqual(list, wantAccountsAfterDelete) {
|
||||
t.Fatalf("got accounts after delete: %s\nwant %s", spew.Sdump(list), spew.Sdump(wantAccountsAfterDelete))
|
||||
}
|
||||
for _, a := range wantAccountsAfterDelete {
|
||||
if !cache.hasAddress(a.Address) {
|
||||
t.Errorf("expected hasAccount(%x) to return true", a.Address)
|
||||
}
|
||||
}
|
||||
if cache.hasAddress(wantAccounts[0].Address) {
|
||||
t.Errorf("expected hasAccount(%x) to return false", wantAccounts[0].Address)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheFind(t *testing.T) {
|
||||
dir := filepath.Join("testdata", "dir")
|
||||
cache := newAddrCache(dir)
|
||||
cache.watcher.running = true // prevent unexpected reloads
|
||||
|
||||
accounts := []Account{
|
||||
{
|
||||
Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
|
||||
File: filepath.Join(dir, "a.key"),
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
|
||||
File: filepath.Join(dir, "b.key"),
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
|
||||
File: filepath.Join(dir, "c.key"),
|
||||
},
|
||||
{
|
||||
Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
|
||||
File: filepath.Join(dir, "c2.key"),
|
||||
},
|
||||
}
|
||||
for _, a := range accounts {
|
||||
cache.add(a)
|
||||
}
|
||||
|
||||
nomatchAccount := Account{
|
||||
Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
|
||||
File: filepath.Join(dir, "something"),
|
||||
}
|
||||
tests := []struct {
|
||||
Query Account
|
||||
WantResult Account
|
||||
WantError error
|
||||
}{
|
||||
// by address
|
||||
{Query: Account{Address: accounts[0].Address}, WantResult: accounts[0]},
|
||||
// by file
|
||||
{Query: Account{File: accounts[0].File}, WantResult: accounts[0]},
|
||||
// by basename
|
||||
{Query: Account{File: filepath.Base(accounts[0].File)}, WantResult: accounts[0]},
|
||||
// by file and address
|
||||
{Query: accounts[0], WantResult: accounts[0]},
|
||||
// ambiguous address, tie resolved by file
|
||||
{Query: accounts[2], WantResult: accounts[2]},
|
||||
// ambiguous address error
|
||||
{
|
||||
Query: Account{Address: accounts[2].Address},
|
||||
WantError: &AmbiguousAddrError{
|
||||
Addr: accounts[2].Address,
|
||||
Matches: []Account{accounts[2], accounts[3]},
|
||||
},
|
||||
},
|
||||
// no match error
|
||||
{Query: nomatchAccount, WantError: ErrNoMatch},
|
||||
{Query: Account{File: nomatchAccount.File}, WantError: ErrNoMatch},
|
||||
{Query: Account{File: filepath.Base(nomatchAccount.File)}, WantError: ErrNoMatch},
|
||||
{Query: Account{Address: nomatchAccount.Address}, WantError: ErrNoMatch},
|
||||
}
|
||||
for i, test := range tests {
|
||||
a, err := cache.find(test.Query)
|
||||
if !reflect.DeepEqual(err, test.WantError) {
|
||||
t.Errorf("test %d: error mismatch for query %v\ngot %q\nwant %q", i, test.Query, err, test.WantError)
|
||||
continue
|
||||
}
|
||||
if a != test.WantResult {
|
||||
t.Errorf("test %d: result mismatch for query %v\ngot %v\nwant %v", i, test.Query, a, test.WantResult)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
229
accounts/key.go
229
accounts/key.go
|
|
@ -1,229 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/crypto/secp256k1"
|
||||
"github.com/pborman/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
version = 3
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
Id uuid.UUID // Version 4 "random" for unique id not derived from key data
|
||||
// to simplify lookups we also store the address
|
||||
Address common.Address
|
||||
// we only store privkey as pubkey/address can be derived from it
|
||||
// privkey in this struct is always in plaintext
|
||||
PrivateKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
type keyStore interface {
|
||||
// Loads and decrypts the key from disk.
|
||||
GetKey(addr common.Address, filename string, auth string) (*Key, error)
|
||||
// Writes and encrypts the key.
|
||||
StoreKey(filename string, k *Key, auth string) error
|
||||
// Joins filename with the key directory unless it is already absolute.
|
||||
JoinPath(filename string) string
|
||||
}
|
||||
|
||||
type plainKeyJSON struct {
|
||||
Address string `json:"address"`
|
||||
PrivateKey string `json:"privatekey"`
|
||||
Id string `json:"id"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
type encryptedKeyJSONV3 struct {
|
||||
Address string `json:"address"`
|
||||
Crypto cryptoJSON `json:"crypto"`
|
||||
Id string `json:"id"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
type encryptedKeyJSONV1 struct {
|
||||
Address string `json:"address"`
|
||||
Crypto cryptoJSON `json:"crypto"`
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type cryptoJSON struct {
|
||||
Cipher string `json:"cipher"`
|
||||
CipherText string `json:"ciphertext"`
|
||||
CipherParams cipherparamsJSON `json:"cipherparams"`
|
||||
KDF string `json:"kdf"`
|
||||
KDFParams map[string]interface{} `json:"kdfparams"`
|
||||
MAC string `json:"mac"`
|
||||
}
|
||||
|
||||
type cipherparamsJSON struct {
|
||||
IV string `json:"iv"`
|
||||
}
|
||||
|
||||
type scryptParamsJSON struct {
|
||||
N int `json:"n"`
|
||||
R int `json:"r"`
|
||||
P int `json:"p"`
|
||||
DkLen int `json:"dklen"`
|
||||
Salt string `json:"salt"`
|
||||
}
|
||||
|
||||
func (k *Key) MarshalJSON() (j []byte, err error) {
|
||||
jStruct := plainKeyJSON{
|
||||
hex.EncodeToString(k.Address[:]),
|
||||
hex.EncodeToString(crypto.FromECDSA(k.PrivateKey)),
|
||||
k.Id.String(),
|
||||
version,
|
||||
}
|
||||
j, err = json.Marshal(jStruct)
|
||||
return j, err
|
||||
}
|
||||
|
||||
func (k *Key) UnmarshalJSON(j []byte) (err error) {
|
||||
keyJSON := new(plainKeyJSON)
|
||||
err = json.Unmarshal(j, &keyJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u := new(uuid.UUID)
|
||||
*u = uuid.Parse(keyJSON.Id)
|
||||
k.Id = *u
|
||||
addr, err := hex.DecodeString(keyJSON.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privkey, err := hex.DecodeString(keyJSON.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.Address = common.BytesToAddress(addr)
|
||||
k.PrivateKey = crypto.ToECDSA(privkey)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key {
|
||||
id := uuid.NewRandom()
|
||||
key := &Key{
|
||||
Id: id,
|
||||
Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey),
|
||||
PrivateKey: privateKeyECDSA,
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
// NewKeyForDirectICAP generates a key whose address fits into < 155 bits so it can fit
|
||||
// into the Direct ICAP spec. for simplicity and easier compatibility with other libs, we
|
||||
// retry until the first byte is 0.
|
||||
func NewKeyForDirectICAP(rand io.Reader) *Key {
|
||||
randBytes := make([]byte, 64)
|
||||
_, err := rand.Read(randBytes)
|
||||
if err != nil {
|
||||
panic("key generation: could not read from random source: " + err.Error())
|
||||
}
|
||||
reader := bytes.NewReader(randBytes)
|
||||
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
|
||||
if err != nil {
|
||||
panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
|
||||
}
|
||||
key := newKeyFromECDSA(privateKeyECDSA)
|
||||
if !strings.HasPrefix(key.Address.Hex(), "0x00") {
|
||||
return NewKeyForDirectICAP(rand)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func newKey(rand io.Reader) (*Key, error) {
|
||||
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newKeyFromECDSA(privateKeyECDSA), nil
|
||||
}
|
||||
|
||||
func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, Account, error) {
|
||||
key, err := newKey(rand)
|
||||
if err != nil {
|
||||
return nil, Account{}, err
|
||||
}
|
||||
a := Account{Address: key.Address, File: ks.JoinPath(keyFileName(key.Address))}
|
||||
if err := ks.StoreKey(a.File, key, auth); err != nil {
|
||||
zeroKey(key.PrivateKey)
|
||||
return nil, a, err
|
||||
}
|
||||
return key, a, err
|
||||
}
|
||||
|
||||
func writeKeyFile(file string, content []byte) error {
|
||||
// Create the keystore directory with appropriate permissions
|
||||
// in case it is not present yet.
|
||||
const dirPerm = 0700
|
||||
if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
// Atomic write: create a temporary hidden file first
|
||||
// then move it into place. TempFile assigns mode 0600.
|
||||
f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := f.Write(content); err != nil {
|
||||
f.Close()
|
||||
os.Remove(f.Name())
|
||||
return err
|
||||
}
|
||||
f.Close()
|
||||
return os.Rename(f.Name(), file)
|
||||
}
|
||||
|
||||
// keyFileName implements the naming convention for keyfiles:
|
||||
// UTC--<created_at UTC ISO8601>-<address hex>
|
||||
func keyFileName(keyAddr common.Address) string {
|
||||
ts := time.Now().UTC()
|
||||
return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
|
||||
}
|
||||
|
||||
func toISO8601(t time.Time) string {
|
||||
var tz string
|
||||
name, offset := t.Zone()
|
||||
if name == "UTC" {
|
||||
tz = "Z"
|
||||
} else {
|
||||
tz = fmt.Sprintf("%03d00", offset/3600)
|
||||
}
|
||||
return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz)
|
||||
}
|
||||
|
|
@ -1,295 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
|
||||
This key store behaves as KeyStorePlain with the difference that
|
||||
the private key is encrypted and on disk uses another JSON encoding.
|
||||
|
||||
The crypto is documented at https://github.com/expanse-org/wiki/wiki/Web3-Secret-Storage-Definition
|
||||
|
||||
*/
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/crypto/randentropy"
|
||||
"github.com/pborman/uuid"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
const (
|
||||
keyHeaderKDF = "scrypt"
|
||||
|
||||
// n,r,p = 2^18, 8, 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
|
||||
StandardScryptN = 1 << 18
|
||||
StandardScryptP = 1
|
||||
|
||||
// n,r,p = 2^12, 8, 6 uses 4MB memory and approx 100ms CPU time on a modern CPU.
|
||||
LightScryptN = 1 << 12
|
||||
LightScryptP = 6
|
||||
|
||||
scryptR = 8
|
||||
scryptDKLen = 32
|
||||
)
|
||||
|
||||
type keyStorePassphrase struct {
|
||||
keysDirPath string
|
||||
scryptN int
|
||||
scryptP int
|
||||
}
|
||||
|
||||
func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) {
|
||||
// Load the key from the keystore and decrypt its contents
|
||||
keyjson, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key, err := DecryptKey(keyjson, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Make sure we're really operating on the requested key (no swap attacks)
|
||||
if key.Address != addr {
|
||||
return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
|
||||
keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeKeyFile(filename, keyjson)
|
||||
}
|
||||
|
||||
func (ks keyStorePassphrase) JoinPath(filename string) string {
|
||||
if filepath.IsAbs(filename) {
|
||||
return filename
|
||||
} else {
|
||||
return filepath.Join(ks.keysDirPath, filename)
|
||||
}
|
||||
}
|
||||
|
||||
// EncryptKey encrypts a key using the specified scrypt parameters into a json
|
||||
// blob that can be decrypted later on.
|
||||
func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
|
||||
authArray := []byte(auth)
|
||||
salt := randentropy.GetEntropyCSPRNG(32)
|
||||
derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encryptKey := derivedKey[:16]
|
||||
keyBytes := crypto.FromECDSA(key.PrivateKey)
|
||||
|
||||
iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
|
||||
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mac := crypto.Keccak256(derivedKey[16:32], cipherText)
|
||||
|
||||
scryptParamsJSON := make(map[string]interface{}, 5)
|
||||
scryptParamsJSON["n"] = scryptN
|
||||
scryptParamsJSON["r"] = scryptR
|
||||
scryptParamsJSON["p"] = scryptP
|
||||
scryptParamsJSON["dklen"] = scryptDKLen
|
||||
scryptParamsJSON["salt"] = hex.EncodeToString(salt)
|
||||
|
||||
cipherParamsJSON := cipherparamsJSON{
|
||||
IV: hex.EncodeToString(iv),
|
||||
}
|
||||
|
||||
cryptoStruct := cryptoJSON{
|
||||
Cipher: "aes-128-ctr",
|
||||
CipherText: hex.EncodeToString(cipherText),
|
||||
CipherParams: cipherParamsJSON,
|
||||
KDF: "scrypt",
|
||||
KDFParams: scryptParamsJSON,
|
||||
MAC: hex.EncodeToString(mac),
|
||||
}
|
||||
encryptedKeyJSONV3 := encryptedKeyJSONV3{
|
||||
hex.EncodeToString(key.Address[:]),
|
||||
cryptoStruct,
|
||||
key.Id.String(),
|
||||
version,
|
||||
}
|
||||
return json.Marshal(encryptedKeyJSONV3)
|
||||
}
|
||||
|
||||
// DecryptKey decrypts a key from a json blob, returning the private key itself.
|
||||
func DecryptKey(keyjson []byte, auth string) (*Key, error) {
|
||||
// Parse the json into a simple map to fetch the key version
|
||||
m := make(map[string]interface{})
|
||||
if err := json.Unmarshal(keyjson, &m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Depending on the version try to parse one way or another
|
||||
var (
|
||||
keyBytes, keyId []byte
|
||||
err error
|
||||
)
|
||||
if version, ok := m["version"].(string); ok && version == "1" {
|
||||
k := new(encryptedKeyJSONV1)
|
||||
if err := json.Unmarshal(keyjson, k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyBytes, keyId, err = decryptKeyV1(k, auth)
|
||||
} else {
|
||||
k := new(encryptedKeyJSONV3)
|
||||
if err := json.Unmarshal(keyjson, k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyBytes, keyId, err = decryptKeyV3(k, auth)
|
||||
}
|
||||
// Handle any decryption errors and return the key
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := crypto.ToECDSA(keyBytes)
|
||||
return &Key{
|
||||
Id: uuid.UUID(keyId),
|
||||
Address: crypto.PubkeyToAddress(key.PublicKey),
|
||||
PrivateKey: key,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
|
||||
if keyProtected.Version != version {
|
||||
return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
|
||||
}
|
||||
|
||||
if keyProtected.Crypto.Cipher != "aes-128-ctr" {
|
||||
return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher)
|
||||
}
|
||||
|
||||
keyId = uuid.Parse(keyProtected.Id)
|
||||
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
|
||||
if !bytes.Equal(calculatedMAC, mac) {
|
||||
return nil, nil, ErrDecrypt
|
||||
}
|
||||
|
||||
plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return plainText, keyId, err
|
||||
}
|
||||
|
||||
func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
|
||||
keyId = uuid.Parse(keyProtected.Id)
|
||||
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
|
||||
if !bytes.Equal(calculatedMAC, mac) {
|
||||
return nil, nil, ErrDecrypt
|
||||
}
|
||||
|
||||
plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return plainText, keyId, err
|
||||
}
|
||||
|
||||
func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
|
||||
authArray := []byte(auth)
|
||||
salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])
|
||||
|
||||
if cryptoJSON.KDF == "scrypt" {
|
||||
n := ensureInt(cryptoJSON.KDFParams["n"])
|
||||
r := ensureInt(cryptoJSON.KDFParams["r"])
|
||||
p := ensureInt(cryptoJSON.KDFParams["p"])
|
||||
return scrypt.Key(authArray, salt, n, r, p, dkLen)
|
||||
|
||||
} else if cryptoJSON.KDF == "pbkdf2" {
|
||||
c := ensureInt(cryptoJSON.KDFParams["c"])
|
||||
prf := cryptoJSON.KDFParams["prf"].(string)
|
||||
if prf != "hmac-sha256" {
|
||||
return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf)
|
||||
}
|
||||
key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
|
||||
return key, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF)
|
||||
}
|
||||
|
||||
// TODO: can we do without this when unmarshalling dynamic JSON?
|
||||
// why do integers in KDF params end up as float64 and not int after
|
||||
// unmarshal?
|
||||
func ensureInt(x interface{}) int {
|
||||
res, ok := x.(int)
|
||||
if !ok {
|
||||
res = int(x.(float64))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
)
|
||||
|
||||
const (
|
||||
veryLightScryptN = 2
|
||||
veryLightScryptP = 1
|
||||
)
|
||||
|
||||
// Tests that a json key file can be decrypted and encrypted in multiple rounds.
|
||||
func TestKeyEncryptDecrypt(t *testing.T) {
|
||||
keyjson, err := ioutil.ReadFile("testdata/very-light-scrypt.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
password := ""
|
||||
address := common.HexToAddress("45dea0fb0bba44f4fcf290bba71fd57d7117cbb8")
|
||||
|
||||
// Do a few rounds of decryption and encryption
|
||||
for i := 0; i < 3; i++ {
|
||||
// Try a bad password first
|
||||
if _, err := DecryptKey(keyjson, password+"bad"); err == nil {
|
||||
t.Errorf("test %d: json key decrypted with bad password", i)
|
||||
}
|
||||
// Decrypt with the correct password
|
||||
key, err := DecryptKey(keyjson, password)
|
||||
if err != nil {
|
||||
t.Errorf("test %d: json key failed to decrypt: %v", i, err)
|
||||
}
|
||||
if key.Address != address {
|
||||
t.Errorf("test %d: key address mismatch: have %x, want %x", i, key.Address, address)
|
||||
}
|
||||
// Recrypt with a new password and start over
|
||||
password += "new data appended"
|
||||
if keyjson, err = EncryptKey(key, password, veryLightScryptN, veryLightScryptP); err != nil {
|
||||
t.Errorf("test %d: failed to recrypt key %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
)
|
||||
|
||||
type keyStorePlain struct {
|
||||
keysDirPath string
|
||||
}
|
||||
|
||||
func (ks keyStorePlain) GetKey(addr common.Address, filename, auth string) (*Key, error) {
|
||||
fd, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
key := new(Key)
|
||||
if err := json.NewDecoder(fd).Decode(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if key.Address != addr {
|
||||
return nil, fmt.Errorf("key content mismatch: have address %x, want %x", key.Address, addr)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (ks keyStorePlain) StoreKey(filename string, key *Key, auth string) error {
|
||||
content, err := json.Marshal(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeKeyFile(filename, content)
|
||||
}
|
||||
|
||||
func (ks keyStorePlain) JoinPath(filename string) string {
|
||||
if filepath.IsAbs(filename) {
|
||||
return filename
|
||||
} else {
|
||||
return filepath.Join(ks.keysDirPath, filename)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
|
||||
)
|
||||
|
||||
func tmpKeyStore(t *testing.T, encrypted bool) (dir string, ks keyStore) {
|
||||
d, err := ioutil.TempDir("", "gexp-keystore-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if encrypted {
|
||||
ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP}
|
||||
} else {
|
||||
ks = &keyStorePlain{d}
|
||||
}
|
||||
return d, ks
|
||||
}
|
||||
|
||||
func TestKeyStorePlain(t *testing.T) {
|
||||
dir, ks := tmpKeyStore(t, false)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
pass := "" // not used but required by API
|
||||
k1, account, err := storeNewKey(ks, rand.Reader, pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
k2, err := ks.GetKey(k1.Address, account.File, pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(k1.Address, k2.Address) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyStorePassphrase(t *testing.T) {
|
||||
dir, ks := tmpKeyStore(t, true)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
pass := "foo"
|
||||
k1, account, err := storeNewKey(ks, rand.Reader, pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
k2, err := ks.GetKey(k1.Address, account.File, pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(k1.Address, k2.Address) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
|
||||
dir, ks := tmpKeyStore(t, true)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
pass := "foo"
|
||||
k1, account, err := storeNewKey(ks, rand.Reader, pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = ks.GetKey(k1.Address, account.File, "bar"); err != ErrDecrypt {
|
||||
t.Fatalf("wrong error for invalid passphrase\ngot %q\nwant %q", err, ErrDecrypt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportPreSaleKey(t *testing.T) {
|
||||
dir, ks := tmpKeyStore(t, true)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// file content of a presale key file generated with:
|
||||
// python pyethsaletool.py genwallet
|
||||
// with password "foo"
|
||||
fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
|
||||
pass := "foo"
|
||||
account, _, err := importPreSaleKey(ks, []byte(fileContent), pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if account.Address != common.HexToAddress("d4584b5f6229b7be90727b0fc8c6b91bb427821f") {
|
||||
t.Errorf("imported account has wrong address %x", account.Address)
|
||||
}
|
||||
if !strings.HasPrefix(account.File, dir) {
|
||||
t.Errorf("imported account file not in keystore directory: %q", account.File)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test and utils for the key store tests in the Expanse JSON tests;
|
||||
// testdataKeyStoreTests/basic_tests.json
|
||||
|
||||
type KeyStoreTestV3 struct {
|
||||
Json encryptedKeyJSONV3
|
||||
Password string
|
||||
Priv string
|
||||
}
|
||||
|
||||
type KeyStoreTestV1 struct {
|
||||
Json encryptedKeyJSONV1
|
||||
Password string
|
||||
Priv string
|
||||
}
|
||||
|
||||
func TestV3_PBKDF2_1(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
|
||||
testDecryptV3(tests["wikipage_test_vector_pbkdf2"], t)
|
||||
}
|
||||
|
||||
func TestV3_PBKDF2_2(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
|
||||
testDecryptV3(tests["test1"], t)
|
||||
}
|
||||
|
||||
func TestV3_PBKDF2_3(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
|
||||
testDecryptV3(tests["python_generated_test_with_odd_iv"], t)
|
||||
}
|
||||
|
||||
func TestV3_PBKDF2_4(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
|
||||
testDecryptV3(tests["evilnonce"], t)
|
||||
}
|
||||
|
||||
func TestV3_Scrypt_1(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
|
||||
testDecryptV3(tests["wikipage_test_vector_scrypt"], t)
|
||||
}
|
||||
|
||||
func TestV3_Scrypt_2(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
|
||||
testDecryptV3(tests["test2"], t)
|
||||
}
|
||||
|
||||
func TestV1_1(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := loadKeyStoreTestV1("testdata/v1_test_vector.json", t)
|
||||
testDecryptV1(tests["test1"], t)
|
||||
}
|
||||
|
||||
func TestV1_2(t *testing.T) {
|
||||
t.Parallel()
|
||||
ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP}
|
||||
addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e")
|
||||
file := "testdata/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
|
||||
k, err := ks.GetKey(addr, file, "g")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
privHex := hex.EncodeToString(crypto.FromECDSA(k.PrivateKey))
|
||||
expectedHex := "d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d"
|
||||
if privHex != expectedHex {
|
||||
t.Fatal(fmt.Errorf("Unexpected privkey: %v, expected %v", privHex, expectedHex))
|
||||
}
|
||||
}
|
||||
|
||||
func testDecryptV3(test KeyStoreTestV3, t *testing.T) {
|
||||
privBytes, _, err := decryptKeyV3(&test.Json, test.Password)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
privHex := hex.EncodeToString(privBytes)
|
||||
if test.Priv != privHex {
|
||||
t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
|
||||
}
|
||||
}
|
||||
|
||||
func testDecryptV1(test KeyStoreTestV1, t *testing.T) {
|
||||
privBytes, _, err := decryptKeyV1(&test.Json, test.Password)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
privHex := hex.EncodeToString(privBytes)
|
||||
if test.Priv != privHex {
|
||||
t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
|
||||
}
|
||||
}
|
||||
|
||||
func loadKeyStoreTestV3(file string, t *testing.T) map[string]KeyStoreTestV3 {
|
||||
tests := make(map[string]KeyStoreTestV3)
|
||||
err := common.LoadJSON(file, &tests)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return tests
|
||||
}
|
||||
|
||||
func loadKeyStoreTestV1(file string, t *testing.T) map[string]KeyStoreTestV1 {
|
||||
tests := make(map[string]KeyStoreTestV1)
|
||||
err := common.LoadJSON(file, &tests)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return tests
|
||||
}
|
||||
|
||||
func TestKeyForDirectICAP(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := NewKeyForDirectICAP(rand.Reader)
|
||||
if !strings.HasPrefix(key.Address.Hex(), "0x00") {
|
||||
t.Errorf("Expected first address byte to be zero, have: %s", key.Address.Hex())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/pborman/uuid"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
|
||||
func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (Account, *Key, error) {
|
||||
key, err := decryptPreSaleKey(keyJSON, password)
|
||||
if err != nil {
|
||||
return Account{}, nil, err
|
||||
}
|
||||
key.Id = uuid.NewRandom()
|
||||
a := Account{Address: key.Address, File: keyStore.JoinPath(keyFileName(key.Address))}
|
||||
err = keyStore.StoreKey(a.File, key, password)
|
||||
return a, key, err
|
||||
}
|
||||
|
||||
func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) {
|
||||
preSaleKeyStruct := struct {
|
||||
EncSeed string
|
||||
EthAddr string
|
||||
Email string
|
||||
BtcAddr string
|
||||
}{}
|
||||
err = json.Unmarshal(fileContent, &preSaleKeyStruct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
|
||||
iv := encSeedBytes[:16]
|
||||
cipherText := encSeedBytes[16:]
|
||||
/*
|
||||
See https://github.com/ethereum/pyethsaletool
|
||||
|
||||
pyethsaletool generates the encryption key from password by
|
||||
2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:().
|
||||
16 byte key length within PBKDF2 and resulting key is used as AES key
|
||||
*/
|
||||
passBytes := []byte(password)
|
||||
derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
|
||||
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ethPriv := crypto.Keccak256(plainText)
|
||||
ecKey := crypto.ToECDSA(ethPriv)
|
||||
key = &Key{
|
||||
Id: nil,
|
||||
Address: crypto.PubkeyToAddress(ecKey.PublicKey),
|
||||
PrivateKey: ecKey,
|
||||
}
|
||||
derivedAddr := hex.EncodeToString(key.Address.Bytes()) // needed because .Hex() gives leading "0x"
|
||||
expectedAddr := preSaleKeyStruct.EthAddr
|
||||
if derivedAddr != expectedAddr {
|
||||
err = fmt.Errorf("decrypted addr '%s' not equal to expected addr '%s'", derivedAddr, expectedAddr)
|
||||
}
|
||||
return key, err
|
||||
}
|
||||
|
||||
func aesCTRXOR(key, inText, iv []byte) ([]byte, error) {
|
||||
// AES-128 is selected due to size of encryptKey.
|
||||
aesBlock, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stream := cipher.NewCTR(aesBlock, iv)
|
||||
outText := make([]byte, len(inText))
|
||||
stream.XORKeyStream(outText, inText)
|
||||
return outText, err
|
||||
}
|
||||
|
||||
func aesCBCDecrypt(key, cipherText, iv []byte) ([]byte, error) {
|
||||
aesBlock, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decrypter := cipher.NewCBCDecrypter(aesBlock, iv)
|
||||
paddedPlaintext := make([]byte, len(cipherText))
|
||||
decrypter.CryptBlocks(paddedPlaintext, cipherText)
|
||||
plaintext := pkcs7Unpad(paddedPlaintext)
|
||||
if plaintext == nil {
|
||||
return nil, ErrDecrypt
|
||||
}
|
||||
return plaintext, err
|
||||
}
|
||||
|
||||
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
|
||||
func pkcs7Unpad(in []byte) []byte {
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
padding := in[len(in)-1]
|
||||
if int(padding) > len(in) || padding > aes.BlockSize {
|
||||
return nil
|
||||
} else if padding == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
|
||||
if in[i] != padding {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return in[:len(in)-int(padding)]
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build darwin,!ios freebsd linux,!arm64 netbsd solaris windows
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/expanse-org/go-expanse/logger"
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
"github.com/rjeczalik/notify"
|
||||
)
|
||||
|
||||
type watcher struct {
|
||||
ac *addrCache
|
||||
starting bool
|
||||
running bool
|
||||
ev chan notify.EventInfo
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
func newWatcher(ac *addrCache) *watcher {
|
||||
return &watcher{
|
||||
ac: ac,
|
||||
ev: make(chan notify.EventInfo, 10),
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// starts the watcher loop in the background.
|
||||
// Start a watcher in the background if that's not already in progress.
|
||||
// The caller must hold w.ac.mu.
|
||||
func (w *watcher) start() {
|
||||
if w.starting || w.running {
|
||||
return
|
||||
}
|
||||
w.starting = true
|
||||
go w.loop()
|
||||
}
|
||||
|
||||
func (w *watcher) close() {
|
||||
close(w.quit)
|
||||
}
|
||||
|
||||
func (w *watcher) loop() {
|
||||
defer func() {
|
||||
w.ac.mu.Lock()
|
||||
w.running = false
|
||||
w.starting = false
|
||||
w.ac.mu.Unlock()
|
||||
}()
|
||||
|
||||
err := notify.Watch(w.ac.keydir, w.ev, notify.All)
|
||||
if err != nil {
|
||||
glog.V(logger.Detail).Infof("can't watch %s: %v", w.ac.keydir, err)
|
||||
return
|
||||
}
|
||||
defer notify.Stop(w.ev)
|
||||
glog.V(logger.Detail).Infof("now watching %s", w.ac.keydir)
|
||||
defer glog.V(logger.Detail).Infof("no longer watching %s", w.ac.keydir)
|
||||
|
||||
w.ac.mu.Lock()
|
||||
w.running = true
|
||||
w.ac.mu.Unlock()
|
||||
|
||||
// Wait for file system events and reload.
|
||||
// When an event occurs, the reload call is delayed a bit so that
|
||||
// multiple events arriving quickly only cause a single reload.
|
||||
var (
|
||||
debounce = time.NewTimer(0)
|
||||
debounceDuration = 500 * time.Millisecond
|
||||
inCycle, hadEvent bool
|
||||
)
|
||||
defer debounce.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-w.quit:
|
||||
return
|
||||
case <-w.ev:
|
||||
if !inCycle {
|
||||
debounce.Reset(debounceDuration)
|
||||
inCycle = true
|
||||
} else {
|
||||
hadEvent = true
|
||||
}
|
||||
case <-debounce.C:
|
||||
w.ac.mu.Lock()
|
||||
w.ac.reload()
|
||||
w.ac.mu.Unlock()
|
||||
if hadEvent {
|
||||
debounce.Reset(debounceDuration)
|
||||
inCycle, hadEvent = true, false
|
||||
} else {
|
||||
inCycle, hadEvent = false, false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ Architecture: any
|
|||
Depends: ${misc:Depends}, {{.ExeList}}
|
||||
Description: Meta-package to install gexp and other tools
|
||||
Meta-package to install gexp and other tools
|
||||
|
||||
|
||||
{{range .Executables}}
|
||||
Package: {{$.ExeName .}}
|
||||
Conflicts: {{$.ExeConflicts .}}
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of go-expanse.
|
||||
//
|
||||
// go-expanse 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.
|
||||
//
|
||||
// go-expanse 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 go-expanse. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// disasm is a pretty-printer for EVM bytecode.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/core/vm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
code, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
code = common.Hex2Bytes(string(code[:len(code)-1]))
|
||||
fmt.Printf("%x\n", code)
|
||||
|
||||
for pc := uint64(0); pc < uint64(len(code)); pc++ {
|
||||
op := vm.OpCode(code[pc])
|
||||
fmt.Printf("%-5d %v", pc, op)
|
||||
|
||||
switch op {
|
||||
case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8, vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15, vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22, vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29, vm.PUSH30, vm.PUSH31, vm.PUSH32:
|
||||
a := uint64(op) - uint64(vm.PUSH1) + 1
|
||||
fmt.Printf(" => %x", code[pc+1:pc+1+a])
|
||||
|
||||
pc += a
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of go-expanse.
|
||||
//
|
||||
// go-expanse 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.
|
||||
//
|
||||
// go-expanse 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 go-expanse. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// exptest executes Expanse JSON tests.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
"github.com/expanse-org/go-expanse/params"
|
||||
"github.com/expanse-org/go-expanse/tests"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
|
||||
)
|
||||
|
||||
var (
|
||||
continueOnError = false
|
||||
testExtension = ".json"
|
||||
defaultTest = "all"
|
||||
defaultDir = "."
|
||||
allTests = []string{"BlockTests", "StateTests", "TransactionTests", "VMTests", "RLPTests"}
|
||||
testDirMapping = map[string]string{"BlockTests": "BlockchainTests"}
|
||||
skipTests = []string{}
|
||||
|
||||
TestFlag = cli.StringFlag{
|
||||
Name: "test",
|
||||
Usage: "Test type (string): VMTests, TransactionTests, StateTests, BlockTests",
|
||||
Value: defaultTest,
|
||||
}
|
||||
FileFlag = cli.StringFlag{
|
||||
Name: "file",
|
||||
Usage: "Test file or directory. Directories are searched for .json files 1 level deep",
|
||||
Value: defaultDir,
|
||||
EnvVar: "EXPANSE_TEST_PATH",
|
||||
}
|
||||
ContinueOnErrorFlag = cli.BoolFlag{
|
||||
Name: "continue",
|
||||
Usage: "Continue running tests on error (true) or [default] exit immediately (false)",
|
||||
}
|
||||
ReadStdInFlag = cli.BoolFlag{
|
||||
Name: "stdin",
|
||||
Usage: "Accept input from stdin instead of reading from file",
|
||||
}
|
||||
SkipTestsFlag = cli.StringFlag{
|
||||
Name: "skip",
|
||||
Usage: "Tests names to skip",
|
||||
}
|
||||
TraceFlag = cli.BoolFlag{
|
||||
Name: "trace",
|
||||
Usage: "Enable VM tracing",
|
||||
}
|
||||
)
|
||||
|
||||
func runTestWithReader(test string, r io.Reader) error {
|
||||
glog.Infoln("runTest", test)
|
||||
var err error
|
||||
switch strings.ToLower(test) {
|
||||
case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
|
||||
err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, r, skipTests)
|
||||
case "st", "state", "statetest", "statetests":
|
||||
rs := tests.RuleSet{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true}
|
||||
err = tests.RunStateTestWithReader(rs, r, skipTests)
|
||||
case "tx", "transactiontest", "transactiontests":
|
||||
err = tests.RunTransactionTestsWithReader(r, skipTests)
|
||||
case "vm", "vmtest", "vmtests":
|
||||
err = tests.RunVmTestWithReader(r, skipTests)
|
||||
case "rlp", "rlptest", "rlptests":
|
||||
err = tests.RunRLPTestWithReader(r, skipTests)
|
||||
default:
|
||||
err = fmt.Errorf("Invalid test type specified: %v", test)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getFiles(path string) ([]string, error) {
|
||||
glog.Infoln("getFiles", path)
|
||||
var files []string
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch mode := fi.Mode(); {
|
||||
case mode.IsDir():
|
||||
fi, _ := ioutil.ReadDir(path)
|
||||
files = make([]string, len(fi))
|
||||
for i, v := range fi {
|
||||
// only go 1 depth and leave directory entires blank
|
||||
if !v.IsDir() && v.Name()[len(v.Name())-len(testExtension):len(v.Name())] == testExtension {
|
||||
files[i] = filepath.Join(path, v.Name())
|
||||
glog.Infoln("Found file", files[i])
|
||||
}
|
||||
}
|
||||
case mode.IsRegular():
|
||||
files = make([]string, 1)
|
||||
files[0] = path
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func runSuite(test, file string) {
|
||||
var tests []string
|
||||
|
||||
if test == defaultTest {
|
||||
tests = allTests
|
||||
} else {
|
||||
tests = []string{test}
|
||||
}
|
||||
|
||||
for _, curTest := range tests {
|
||||
glog.Infoln("runSuite", curTest, file)
|
||||
var err error
|
||||
var files []string
|
||||
if test == defaultTest {
|
||||
// check if we have an explicit directory mapping for the test
|
||||
if _, ok := testDirMapping[curTest]; ok {
|
||||
files, err = getFiles(filepath.Join(file, testDirMapping[curTest]))
|
||||
} else {
|
||||
// otherwise assume test name
|
||||
files, err = getFiles(filepath.Join(file, curTest))
|
||||
}
|
||||
} else {
|
||||
files, err = getFiles(file)
|
||||
}
|
||||
if err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
glog.Warningln("No files matched path")
|
||||
}
|
||||
for _, curFile := range files {
|
||||
// Skip blank entries
|
||||
if len(curFile) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
r, err := os.Open(curFile)
|
||||
if err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
err = runTestWithReader(curTest, r)
|
||||
if err != nil {
|
||||
if continueOnError {
|
||||
glog.Errorln(err)
|
||||
} else {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setupApp(c *cli.Context) error {
|
||||
flagTest := c.GlobalString(TestFlag.Name)
|
||||
flagFile := c.GlobalString(FileFlag.Name)
|
||||
continueOnError = c.GlobalBool(ContinueOnErrorFlag.Name)
|
||||
useStdIn := c.GlobalBool(ReadStdInFlag.Name)
|
||||
skipTests = strings.Split(c.GlobalString(SkipTestsFlag.Name), " ")
|
||||
|
||||
if !useStdIn {
|
||||
runSuite(flagTest, flagFile)
|
||||
} else {
|
||||
if err := runTestWithReader(flagTest, os.Stdin); err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
glog.SetToStderr(true)
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "exptest"
|
||||
app.Usage = "go-expanse test interface"
|
||||
app.Action = setupApp
|
||||
app.Version = "0.2.0"
|
||||
app.Author = "go-expanse team"
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
TestFlag,
|
||||
FileFlag,
|
||||
ContinueOnErrorFlag,
|
||||
ReadStdInFlag,
|
||||
SkipTestsFlag,
|
||||
TraceFlag,
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/core"
|
||||
"github.com/expanse-org/go-expanse/ethdb"
|
||||
"github.com/expanse-org/go-expanse/params"
|
||||
)
|
||||
|
||||
// Genesis block for nodes which don't care about the DAO fork (i.e. not configured)
|
||||
var daoOldGenesis = `{
|
||||
"alloc" : {},
|
||||
"coinbase" : "0x0000000000000000000000000000000000000000",
|
||||
"difficulty" : "0x20000",
|
||||
"extraData" : "",
|
||||
"gasLimit" : "0x2fefd8",
|
||||
"nonce" : "0x0000000000000042",
|
||||
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp" : "0x00",
|
||||
"config" : {}
|
||||
}`
|
||||
|
||||
// Genesis block for nodes which actively oppose the DAO fork
|
||||
var daoNoForkGenesis = `{
|
||||
"alloc" : {},
|
||||
"coinbase" : "0x0000000000000000000000000000000000000000",
|
||||
"difficulty" : "0x20000",
|
||||
"extraData" : "",
|
||||
"gasLimit" : "0x2fefd8",
|
||||
"nonce" : "0x0000000000000042",
|
||||
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp" : "0x00",
|
||||
"config" : {
|
||||
"daoForkBlock" : 314,
|
||||
"daoForkSupport" : false
|
||||
}
|
||||
}`
|
||||
|
||||
// Genesis block for nodes which actively support the DAO fork
|
||||
var daoProForkGenesis = `{
|
||||
"alloc" : {},
|
||||
"coinbase" : "0x0000000000000000000000000000000000000000",
|
||||
"difficulty" : "0x20000",
|
||||
"extraData" : "",
|
||||
"gasLimit" : "0x2fefd8",
|
||||
"nonce" : "0x0000000000000042",
|
||||
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp" : "0x00",
|
||||
"config" : {
|
||||
"daoForkBlock" : 314,
|
||||
"daoForkSupport" : true
|
||||
}
|
||||
}`
|
||||
|
||||
var daoGenesisHash = common.HexToHash("5e1fc79cb4ffa4739177b5408045cd5d51c6cf766133f23f7cd72ee1f8d790e0")
|
||||
var daoGenesisForkBlock = big.NewInt(314)
|
||||
|
||||
// Tests that the DAO hard-fork number and the nodes support/opposition is correctly
|
||||
// set in the database after various initialization procedures and invocations.
|
||||
func TestDAODefaultMainnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, "", [][2]bool{{false, false}}, params.MainNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOSupportMainnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, "", [][2]bool{{true, false}}, params.MainNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOOpposeMainnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, "", [][2]bool{{false, true}}, params.MainNetDAOForkBlock, false)
|
||||
}
|
||||
func TestDAOSwitchToSupportMainnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, "", [][2]bool{{false, true}, {true, false}}, params.MainNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOSwitchToOpposeMainnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, "", [][2]bool{{true, false}, {false, true}}, params.MainNetDAOForkBlock, false)
|
||||
}
|
||||
func TestDAODefaultTestnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, true, "", [][2]bool{{false, false}}, params.TestNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOSupportTestnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, true, "", [][2]bool{{true, false}}, params.TestNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOOpposeTestnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, true, "", [][2]bool{{false, true}}, params.TestNetDAOForkBlock, false)
|
||||
}
|
||||
func TestDAOSwitchToSupportTestnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, true, "", [][2]bool{{false, true}, {true, false}}, params.TestNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOSwitchToOpposeTestnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, true, "", [][2]bool{{true, false}, {false, true}}, params.TestNetDAOForkBlock, false)
|
||||
}
|
||||
func TestDAOInitOldPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{}, nil, false)
|
||||
}
|
||||
func TestDAODefaultOldPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{false, false}}, params.MainNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOSupportOldPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{true, false}}, params.MainNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOOpposeOldPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{false, true}}, params.MainNetDAOForkBlock, false)
|
||||
}
|
||||
func TestDAOSwitchToSupportOldPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{false, true}, {true, false}}, params.MainNetDAOForkBlock, true)
|
||||
}
|
||||
func TestDAOSwitchToOpposeOldPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoOldGenesis, [][2]bool{{true, false}, {false, true}}, params.MainNetDAOForkBlock, false)
|
||||
}
|
||||
func TestDAOInitNoForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{}, daoGenesisForkBlock, false)
|
||||
}
|
||||
func TestDAODefaultNoForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{false, false}}, daoGenesisForkBlock, false)
|
||||
}
|
||||
func TestDAOSupportNoForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{true, false}}, daoGenesisForkBlock, true)
|
||||
}
|
||||
func TestDAOOpposeNoForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{false, true}}, daoGenesisForkBlock, false)
|
||||
}
|
||||
func TestDAOSwitchToSupportNoForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{false, true}, {true, false}}, daoGenesisForkBlock, true)
|
||||
}
|
||||
func TestDAOSwitchToOpposeNoForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoNoForkGenesis, [][2]bool{{true, false}, {false, true}}, daoGenesisForkBlock, false)
|
||||
}
|
||||
func TestDAOInitProForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{}, daoGenesisForkBlock, true)
|
||||
}
|
||||
func TestDAODefaultProForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{false, false}}, daoGenesisForkBlock, true)
|
||||
}
|
||||
func TestDAOSupportProForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{true, false}}, daoGenesisForkBlock, true)
|
||||
}
|
||||
func TestDAOOpposeProForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{false, true}}, daoGenesisForkBlock, false)
|
||||
}
|
||||
func TestDAOSwitchToSupportProForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{false, true}, {true, false}}, daoGenesisForkBlock, true)
|
||||
}
|
||||
func TestDAOSwitchToOpposeProForkPrivnet(t *testing.T) {
|
||||
testDAOForkBlockNewChain(t, false, daoProForkGenesis, [][2]bool{{true, false}, {false, true}}, daoGenesisForkBlock, false)
|
||||
}
|
||||
|
||||
func testDAOForkBlockNewChain(t *testing.T, testnet bool, genesis string, votes [][2]bool, expectBlock *big.Int, expectVote bool) {
|
||||
// Create a temporary data directory to use and inspect later
|
||||
datadir := tmpdir(t)
|
||||
defer os.RemoveAll(datadir)
|
||||
|
||||
// Start a instance with the requested flags set and immediately terminate
|
||||
if genesis != "" {
|
||||
json := filepath.Join(datadir, "genesis.json")
|
||||
if err := ioutil.WriteFile(json, []byte(genesis), 0600); err != nil {
|
||||
t.Fatalf("failed to write genesis file: %v", err)
|
||||
}
|
||||
runGeth(t, "--datadir", datadir, "init", json).cmd.Wait()
|
||||
}
|
||||
for _, vote := range votes {
|
||||
args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir}
|
||||
if testnet {
|
||||
args = append(args, "--testnet")
|
||||
}
|
||||
if vote[0] {
|
||||
args = append(args, "--support-dao-fork")
|
||||
}
|
||||
if vote[1] {
|
||||
args = append(args, "--oppose-dao-fork")
|
||||
}
|
||||
geth := runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...)
|
||||
geth.cmd.Wait()
|
||||
}
|
||||
// Retrieve the DAO config flag from the database
|
||||
path := filepath.Join(datadir, "chaindata")
|
||||
if testnet && genesis == "" {
|
||||
path = filepath.Join(datadir, "testnet", "chaindata")
|
||||
}
|
||||
db, err := ethdb.NewLDBDatabase(path, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open test database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
genesisHash := common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
|
||||
if testnet {
|
||||
genesisHash = common.HexToHash("0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303")
|
||||
}
|
||||
if genesis != "" {
|
||||
genesisHash = daoGenesisHash
|
||||
}
|
||||
config, err := core.GetChainConfig(db, genesisHash)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to retrieve chain config: %v", err)
|
||||
}
|
||||
// Validate the DAO hard-fork block number against the expected value
|
||||
if config.DAOForkBlock == nil {
|
||||
if expectBlock != nil {
|
||||
t.Errorf("dao hard-fork block mismatch: have nil, want %v", expectBlock)
|
||||
}
|
||||
} else if expectBlock == nil {
|
||||
t.Errorf("dao hard-fork block mismatch: have %v, want nil", config.DAOForkBlock)
|
||||
} else if config.DAOForkBlock.Cmp(expectBlock) != 0 {
|
||||
t.Errorf("dao hard-fork block mismatch: have %v, want %v", config.DAOForkBlock, expectBlock)
|
||||
}
|
||||
if config.DAOForkSupport != expectVote {
|
||||
t.Errorf("dao hard-fork support mismatch: have %v, want %v", config.DAOForkSupport, expectVote)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// gexprpctest is a command to run the external RPC tests.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/expanse-org/go-expanse/accounts"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/core"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/eth"
|
||||
"github.com/expanse-org/go-expanse/ethdb"
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
"github.com/expanse-org/go-expanse/node"
|
||||
"github.com/expanse-org/go-expanse/params"
|
||||
"github.com/expanse-org/go-expanse/tests"
|
||||
"github.com/expanse-org/go-expanse/whisper"
|
||||
)
|
||||
|
||||
const defaultTestKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||
|
||||
var (
|
||||
testFile = flag.String("json", "", "Path to the .json test file to load")
|
||||
testName = flag.String("test", "", "Name of the test from the .json file to run")
|
||||
testKey = flag.String("key", defaultTestKey, "Private key of a test account to inject")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Enable logging errors, we really do want to see those
|
||||
glog.SetV(2)
|
||||
glog.SetToStderr(true)
|
||||
|
||||
// Load the test suite to run the RPC against
|
||||
tests, err := tests.LoadBlockTests(*testFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load test suite: %v", err)
|
||||
}
|
||||
test, found := tests[*testName]
|
||||
if !found {
|
||||
log.Fatalf("Requested test (%s) not found within suite", *testName)
|
||||
}
|
||||
// Create the protocol stack to run the test with
|
||||
keydir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create temporary keystore directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(keydir)
|
||||
|
||||
stack, err := MakeSystemNode(keydir, *testKey, test)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to assemble test stack: %v", err)
|
||||
}
|
||||
if err := stack.Start(); err != nil {
|
||||
log.Fatalf("Failed to start test node: %v", err)
|
||||
}
|
||||
defer stack.Stop()
|
||||
|
||||
log.Println("Test node started...")
|
||||
|
||||
// Make sure the tests contained within the suite pass
|
||||
if err := RunTest(stack, test); err != nil {
|
||||
log.Fatalf("Failed to run the pre-configured test: %v", err)
|
||||
}
|
||||
log.Println("Initial test suite passed...")
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt)
|
||||
<-quit
|
||||
}
|
||||
|
||||
// MakeSystemNode configures a protocol stack for the RPC tests based on a given
|
||||
// keystore path and initial pre-state.
|
||||
func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node.Node, error) {
|
||||
// Create a networkless protocol stack
|
||||
stack, err := node.New(&node.Config{
|
||||
IPCPath: node.DefaultIPCEndpoint(),
|
||||
HTTPHost: common.DefaultHTTPHost,
|
||||
HTTPPort: common.DefaultHTTPPort,
|
||||
HTTPModules: []string{"admin", "db", "exp", "debug", "miner", "net", "shh", "txpool", "personal", "web3"},
|
||||
WSHost: common.DefaultWSHost,
|
||||
WSPort: common.DefaultWSPort,
|
||||
WSModules: []string{"admin", "db", "exp", "debug", "miner", "net", "shh", "txpool", "personal", "web3"},
|
||||
NoDiscovery: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Create the keystore and inject an unlocked account if requested
|
||||
accman := accounts.NewPlaintextManager(keydir)
|
||||
if len(privkey) > 0 {
|
||||
key, err := crypto.HexToECDSA(privkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a, err := accman.ImportECDSA(key, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := accman.Unlock(a, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Initialize and register the Expanse protocol
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
if _, err := test.InsertPreState(db); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ethConf := &exp.Config{
|
||||
TestGenesisState: db,
|
||||
TestGenesisBlock: test.Genesis,
|
||||
ChainConfig: &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock},
|
||||
AccountManager: accman,
|
||||
}
|
||||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return exp.New(ctx, ethConf) }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Initialize and register the Whisper protocol
|
||||
if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stack, nil
|
||||
}
|
||||
|
||||
// RunTest executes the specified test against an already pre-configured protocol
|
||||
// stack to ensure basic checks pass before running RPC tests.
|
||||
func RunTest(stack *node.Node, test *tests.BlockTest) error {
|
||||
var expanse *exp.Expanse
|
||||
stack.Service(&expanse)
|
||||
blockchain := expanse.BlockChain()
|
||||
|
||||
// Process the blocks and verify the imported headers
|
||||
blocks, err := test.TryBlocksInsert(blockchain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := test.ValidateImportedHeaders(blockchain, blocks); err != nil {
|
||||
return err
|
||||
}
|
||||
// Retrieve the assembled state and validate it
|
||||
stateDb, err := blockchain.State()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := test.ValidatePostState(stateDb); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -58,10 +58,10 @@ participating.
|
|||
ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
|
||||
Category: "BLOCKCHAIN COMMANDS",
|
||||
Description: `
|
||||
The import command imports blocks from an RLP-encoded form. The form can be one file
|
||||
with several RLP-encoded blocks, or several files can be used.
|
||||
If only one file is used, import error will result in failure. If several files are used,
|
||||
processing will proceed even if an individual RLP-file import failure occurs.
|
||||
The import command imports blocks from an RLP-encoded form. The form can be one file
|
||||
with several RLP-encoded blocks, or several files can be used.
|
||||
If only one file is used, import error will result in failure. If several files are used,
|
||||
processing will proceed even if an individual RLP-file import failure occurs.
|
||||
`,
|
||||
}
|
||||
exportCommand = cli.Command{
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package utils
|
||||
|
||||
import "github.com/expanse-org/go-expanse/p2p/discover"
|
||||
|
||||
// FrontierBootNodes are the enode URLs of the P2P bootstrap nodes running on
|
||||
// the Frontier network.
|
||||
var FrontierBootNodes = []*discover.Node{
|
||||
// EXP/DEV Go Bootnodes
|
||||
discover.MustParseNode("enode://7f335a047654f3e70d6f91312a7cf89c39704011f1a584e2698250db3d63817e74b88e26b7854111e16b2c9d0c7173c05419aeee2d0321850227b126d8b1be3f@46.101.156.249:42786"),
|
||||
discover.MustParseNode("enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786"),
|
||||
discover.MustParseNode("enode://96d3919b903e7f5ad59ac2f73c43be9172d9d27e2771355db03fd194732b795829a31fe2ea6de109d0804786c39a807e155f065b4b94c6fce167becd0ac02383@45.55.22.34:42786"),
|
||||
discover.MustParseNode("enode://5f6c625bf287e3c08aad568de42d868781e961cbda805c8397cfb7be97e229419bef9a5a25a75f97632787106bba8a7caf9060fab3887ad2cfbeb182ab0f433f@46.101.182.53:42786"),
|
||||
discover.MustParseNode("enode://d33a8d4c2c38a08971ed975b750f21d54c927c0bf7415931e214465a8d01651ecffe4401e1db913f398383381413c78105656d665d83f385244ab302d6138414@128.199.183.48:42786"),
|
||||
discover.MustParseNode("enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786"),
|
||||
discover.MustParseNode("enode://f6f0d6b9b7d02ec9e8e4a16e38675f3621ea5e69860c739a65c1597ca28aefb3cec7a6d84e471ac927d42a1b64c1cbdefad75e7ce8872d57548ddcece20afdd1@159.203.64.95:42786"),
|
||||
}
|
||||
|
||||
// TestNetBootNodes are the enode URLs of the P2P bootstrap nodes running on the
|
||||
// Morden test network.
|
||||
var TestNetBootNodes = []*discover.Node{
|
||||
// ETH/DEV Go Bootnodes
|
||||
discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"),
|
||||
discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"),
|
||||
|
||||
// ETH/DEV Cpp Bootnodes
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/expanse-org/go-expanse/node"
|
||||
"github.com/expanse-org/go-expanse/rpc"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
// NewRemoteRPCClient returns a RPC client which connects to a running gexp instance.
|
||||
// Depending on the given context this can either be a IPC or a HTTP client.
|
||||
func NewRemoteRPCClient(ctx *cli.Context) (rpc.Client, error) {
|
||||
if ctx.Args().Present() {
|
||||
endpoint := ctx.Args().First()
|
||||
return NewRemoteRPCClientFromString(endpoint)
|
||||
}
|
||||
// use IPC by default
|
||||
return rpc.NewIPCClient(node.DefaultIPCEndpoint())
|
||||
}
|
||||
|
||||
// NewRemoteRPCClientFromString returns a RPC client which connects to the given
|
||||
// endpoint. It must start with either `ipc:` or `rpc:` (HTTP).
|
||||
func NewRemoteRPCClientFromString(endpoint string) (rpc.Client, error) {
|
||||
if strings.HasPrefix(endpoint, "ipc:") {
|
||||
return rpc.NewIPCClient(endpoint[4:])
|
||||
}
|
||||
if strings.HasPrefix(endpoint, "rpc:") {
|
||||
return rpc.NewHTTPClient(endpoint[4:])
|
||||
}
|
||||
if strings.HasPrefix(endpoint, "http://") {
|
||||
return rpc.NewHTTPClient(endpoint)
|
||||
}
|
||||
if strings.HasPrefix(endpoint, "ws:") {
|
||||
return rpc.NewWSClient(endpoint)
|
||||
}
|
||||
return nil, fmt.Errorf("invalid endpoint")
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
)
|
||||
|
||||
type HTTPClient struct {
|
||||
*http.Transport
|
||||
DocRoot string
|
||||
schemes []string
|
||||
}
|
||||
|
||||
func New(docRoot string) (self *HTTPClient) {
|
||||
self = &HTTPClient{
|
||||
Transport: &http.Transport{},
|
||||
DocRoot: docRoot,
|
||||
schemes: []string{"file"},
|
||||
}
|
||||
self.RegisterProtocol("file", http.NewFileTransport(http.Dir(self.DocRoot)))
|
||||
return
|
||||
}
|
||||
|
||||
// Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
|
||||
|
||||
// A Client is higher-level than a RoundTripper (such as Transport) and additionally handles HTTP details such as cookies and redirects.
|
||||
|
||||
func (self *HTTPClient) Client() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: self,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *HTTPClient) RegisterScheme(scheme string, rt http.RoundTripper) {
|
||||
self.schemes = append(self.schemes, scheme)
|
||||
self.RegisterProtocol(scheme, rt)
|
||||
}
|
||||
|
||||
func (self *HTTPClient) HasScheme(scheme string) bool {
|
||||
for _, s := range self.schemes {
|
||||
if s == scheme {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *HTTPClient) GetAuthContent(uri string, hash common.Hash) ([]byte, error) {
|
||||
// retrieve content
|
||||
content, err := self.Get(uri, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check hash to authenticate content
|
||||
chash := crypto.Keccak256Hash(content)
|
||||
if chash != hash {
|
||||
return nil, fmt.Errorf("content hash mismatch %x != %x (exp)", hash[:], chash[:])
|
||||
}
|
||||
|
||||
return content, nil
|
||||
|
||||
}
|
||||
|
||||
// Get(uri, path) downloads the document at uri, if path is non-empty it
|
||||
// is interpreted as a filepath to which the contents are saved
|
||||
func (self *HTTPClient) Get(uri, path string) ([]byte, error) {
|
||||
// retrieve content
|
||||
resp, err := self.Client().Get(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
var content []byte
|
||||
content, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode/100 != 2 {
|
||||
return content, fmt.Errorf("HTTP error: %s", resp.Status)
|
||||
}
|
||||
|
||||
if path != "" {
|
||||
var abspath string
|
||||
abspath, err = filepath.Abs(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ioutil.WriteFile(abspath, content, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return content, nil
|
||||
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
)
|
||||
|
||||
func TestGetAuthContent(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "httpclient-test")
|
||||
if err != nil {
|
||||
t.Fatal("cannot create temporary directory:", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
client := New(dir)
|
||||
|
||||
text := "test"
|
||||
hash := crypto.Keccak256Hash([]byte(text))
|
||||
if err := ioutil.WriteFile(path.Join(dir, "test.content"), []byte(text), os.ModePerm); err != nil {
|
||||
t.Fatal("could not write test file", err)
|
||||
}
|
||||
content, err := client.GetAuthContent("file:///test.content", hash)
|
||||
if err != nil {
|
||||
t.Errorf("no error expected, got %v", err)
|
||||
}
|
||||
if string(content) != text {
|
||||
t.Errorf("incorrect content. expected %v, got %v", text, string(content))
|
||||
}
|
||||
|
||||
hash = common.Hash{}
|
||||
content, err = client.GetAuthContent("file:///test.content", hash)
|
||||
expected := "content hash mismatch 0000000000000000000000000000000000000000000000000000000000000000 != 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 (exp)"
|
||||
if err == nil {
|
||||
t.Errorf("expected error, got nothing")
|
||||
} else {
|
||||
if err.Error() != expected {
|
||||
t.Errorf("expected error '%s' got '%v'", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type rt struct{}
|
||||
|
||||
func (rt) RoundTrip(req *http.Request) (resp *http.Response, err error) { return }
|
||||
|
||||
func TestRegisterScheme(t *testing.T) {
|
||||
client := New("/tmp/")
|
||||
if client.HasScheme("scheme") {
|
||||
t.Errorf("expected scheme not to be registered")
|
||||
}
|
||||
client.RegisterScheme("scheme", rt{})
|
||||
if !client.HasScheme("scheme") {
|
||||
t.Errorf("expected scheme to be registered")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package math
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sort"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
)
|
||||
|
||||
type Summer interface {
|
||||
Sum(i int) *big.Int
|
||||
Len() int
|
||||
}
|
||||
|
||||
func Sum(slice Summer) (sum *big.Int) {
|
||||
sum = new(big.Int)
|
||||
|
||||
for i := 0; i < slice.Len(); i++ {
|
||||
sum.Add(sum, slice.Sum(i))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Vector struct {
|
||||
Gas, Price *big.Int
|
||||
}
|
||||
|
||||
type VectorsBy func(v1, v2 Vector) bool
|
||||
|
||||
func (self VectorsBy) Sort(vectors []Vector) {
|
||||
bs := vectorSorter{
|
||||
vectors: vectors,
|
||||
by: self,
|
||||
}
|
||||
sort.Sort(bs)
|
||||
}
|
||||
|
||||
type vectorSorter struct {
|
||||
vectors []Vector
|
||||
by func(v1, v2 Vector) bool
|
||||
}
|
||||
|
||||
func (v vectorSorter) Len() int { return len(v.vectors) }
|
||||
func (v vectorSorter) Less(i, j int) bool { return v.by(v.vectors[i], v.vectors[j]) }
|
||||
func (v vectorSorter) Swap(i, j int) { v.vectors[i], v.vectors[j] = v.vectors[j], v.vectors[i] }
|
||||
|
||||
func PriceSort(v1, v2 Vector) bool { return v1.Price.Cmp(v2.Price) < 0 }
|
||||
func GasSort(v1, v2 Vector) bool { return v1.Gas.Cmp(v2.Gas) < 0 }
|
||||
|
||||
type vectorSummer struct {
|
||||
vectors []Vector
|
||||
by func(v Vector) *big.Int
|
||||
}
|
||||
|
||||
type VectorSum func(v Vector) *big.Int
|
||||
|
||||
func (v VectorSum) Sum(vectors []Vector) *big.Int {
|
||||
vs := vectorSummer{
|
||||
vectors: vectors,
|
||||
by: v,
|
||||
}
|
||||
return Sum(vs)
|
||||
}
|
||||
|
||||
func (v vectorSummer) Len() int { return len(v.vectors) }
|
||||
func (v vectorSummer) Sum(i int) *big.Int { return v.by(v.vectors[i]) }
|
||||
|
||||
func GasSum(v Vector) *big.Int { return v.Gas }
|
||||
|
||||
var etherInWei = new(big.Rat).SetInt(common.String2Big("1000000000000000000"))
|
||||
|
||||
func GasPrice(bp, gl, ep *big.Int) *big.Int {
|
||||
BP := new(big.Rat).SetInt(bp)
|
||||
GL := new(big.Rat).SetInt(gl)
|
||||
EP := new(big.Rat).SetInt(ep)
|
||||
GP := new(big.Rat).Quo(BP, GL)
|
||||
GP = GP.Quo(GP, EP)
|
||||
|
||||
return GP.Mul(GP, etherInWei).Num()
|
||||
}
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package natspec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/common/httpclient"
|
||||
"github.com/expanse-org/go-expanse/common/registrar"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/xeth"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
type abi2method map[[8]byte]*method
|
||||
|
||||
type NatSpec struct {
|
||||
jsvm *otto.Otto
|
||||
abiDocJson []byte
|
||||
userDoc userDoc
|
||||
tx, data string
|
||||
}
|
||||
|
||||
// main entry point for to get natspec notice for a transaction
|
||||
// the implementation is frontend friendly in that it always gives back
|
||||
// a notice that is safe to display
|
||||
// :FIXME: the second return value is an error, which can be used to fine-tune bahaviour
|
||||
func GetNotice(xeth *xexp.XEth, tx string, http *httpclient.HTTPClient) (notice string) {
|
||||
ns, err := New(xeth, tx, http)
|
||||
if err != nil {
|
||||
if ns == nil {
|
||||
return getFallbackNotice(fmt.Sprintf("no NatSpec info found for contract: %v", err), tx)
|
||||
} else {
|
||||
return getFallbackNotice(fmt.Sprintf("invalid NatSpec info: %v", err), tx)
|
||||
}
|
||||
}
|
||||
|
||||
notice, err = ns.Notice()
|
||||
if err != nil {
|
||||
return getFallbackNotice(fmt.Sprintf("NatSpec notice error: %v", err), tx)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getFallbackNotice(comment, tx string) string {
|
||||
return fmt.Sprintf("About to submit transaction (%s): %s", comment, tx)
|
||||
}
|
||||
|
||||
type transaction struct {
|
||||
To string `json:"to"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
type jsonTx struct {
|
||||
Params []transaction `json:"params"`
|
||||
}
|
||||
|
||||
type contractInfo struct {
|
||||
Source string `json:"source"`
|
||||
Language string `json:"language"`
|
||||
Version string `json:"compilerVersion"`
|
||||
AbiDefinition json.RawMessage `json:"abiDefinition"`
|
||||
UserDoc userDoc `json:"userDoc"`
|
||||
DeveloperDoc json.RawMessage `json:"developerDoc"`
|
||||
}
|
||||
|
||||
func New(xeth *xexp.XEth, jsontx string, http *httpclient.HTTPClient) (self *NatSpec, err error) {
|
||||
|
||||
// extract contract address from tx
|
||||
var tx jsonTx
|
||||
err = json.Unmarshal([]byte(jsontx), &tx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t := tx.Params[0]
|
||||
contractAddress := t.To
|
||||
|
||||
content, err := FetchDocsForContract(contractAddress, xeth, http)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
self, err = NewWithDocs(content, jsontx, t.Data)
|
||||
return
|
||||
}
|
||||
|
||||
// also called by admin.contractInfo.get
|
||||
func FetchDocsForContract(contractAddress string, xeth *xexp.XEth, client *httpclient.HTTPClient) (content []byte, err error) {
|
||||
// retrieve contract hash from state
|
||||
codehex := xexp.CodeAt(contractAddress)
|
||||
codeb := xexp.CodeAtBytes(contractAddress)
|
||||
|
||||
if codehex == "0x" {
|
||||
err = fmt.Errorf("contract (%v) not found", contractAddress)
|
||||
return
|
||||
}
|
||||
codehash := common.BytesToHash(crypto.Keccak256(codeb))
|
||||
// set up nameresolver with natspecreg + urlhint contract addresses
|
||||
reg := registrar.New(xeth)
|
||||
|
||||
// resolve host via HashReg/UrlHint Resolver
|
||||
hash, err := reg.HashToHash(codehash)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if client.HasScheme("bzz") {
|
||||
content, err = client.Get("bzz://"+hash.Hex()[2:], "")
|
||||
if err == nil { // non-fatal
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
//falling back to urlhint
|
||||
}
|
||||
|
||||
uri, err := reg.HashToUrl(hash)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// get content via http client and authenticate content using hash
|
||||
content, err = client.GetAuthContent(uri, hash)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NewWithDocs(infoDoc []byte, tx string, data string) (self *NatSpec, err error) {
|
||||
|
||||
var contract contractInfo
|
||||
err = json.Unmarshal(infoDoc, &contract)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
self = &NatSpec{
|
||||
jsvm: otto.New(),
|
||||
abiDocJson: []byte(contract.AbiDefinition),
|
||||
userDoc: contract.UserDoc,
|
||||
tx: tx,
|
||||
data: data,
|
||||
}
|
||||
|
||||
// load and require natspec js (but it is meant to be protected environment)
|
||||
_, err = self.jsvm.Run(natspecJS)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = self.jsvm.Run("var natspec = require('natspec');")
|
||||
return
|
||||
}
|
||||
|
||||
// type abiDoc []method
|
||||
|
||||
// type method struct {
|
||||
// Name string `json:name`
|
||||
// Inputs []input `json:inputs`
|
||||
// abiKey [8]byte
|
||||
// }
|
||||
|
||||
// type input struct {
|
||||
// Name string `json:name`
|
||||
// Type string `json:type`
|
||||
// }
|
||||
|
||||
// json skeleton for abi doc (contract method definitions)
|
||||
type method struct {
|
||||
Notice string `json:notice`
|
||||
name string
|
||||
}
|
||||
|
||||
type userDoc struct {
|
||||
Methods map[string]*method `json:methods`
|
||||
}
|
||||
|
||||
func (self *NatSpec) makeAbi2method(abiKey [8]byte) (meth *method) {
|
||||
for signature, m := range self.userDoc.Methods {
|
||||
name := strings.Split(signature, "(")[0]
|
||||
hash := []byte(common.Bytes2Hex(crypto.Keccak256([]byte(signature))))
|
||||
var key [8]byte
|
||||
copy(key[:], hash[:8])
|
||||
if bytes.Equal(key[:], abiKey[:]) {
|
||||
meth = m
|
||||
mexp.name = name
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *NatSpec) Notice() (notice string, err error) {
|
||||
var abiKey [8]byte
|
||||
if len(self.data) < 10 {
|
||||
err = fmt.Errorf("Invalid transaction data")
|
||||
return
|
||||
}
|
||||
copy(abiKey[:], self.data[2:10])
|
||||
meth := self.makeAbi2method(abiKey)
|
||||
|
||||
if meth == nil {
|
||||
err = fmt.Errorf("abi key does not match any method")
|
||||
return
|
||||
}
|
||||
notice, err = self.noticeForMethod(self.tx, mexp.name, mexp.Notice)
|
||||
return
|
||||
}
|
||||
|
||||
func (self *NatSpec) noticeForMethod(tx string, name, expression string) (notice string, err error) {
|
||||
|
||||
if _, err = self.jsvm.Run("var transaction = " + tx + ";"); err != nil {
|
||||
return "", fmt.Errorf("natspec.js error setting transaction: %v", err)
|
||||
}
|
||||
|
||||
if _, err = self.jsvm.Run("var abi = " + string(self.abiDocJson) + ";"); err != nil {
|
||||
return "", fmt.Errorf("natspec.js error setting abi: %v", err)
|
||||
}
|
||||
|
||||
if _, err = self.jsvm.Run("var method = '" + name + "';"); err != nil {
|
||||
return "", fmt.Errorf("natspec.js error setting method: %v", err)
|
||||
}
|
||||
|
||||
if _, err = self.jsvm.Run("var expression = \"" + expression + "\";"); err != nil {
|
||||
return "", fmt.Errorf("natspec.js error setting expression: %v", err)
|
||||
}
|
||||
|
||||
self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};")
|
||||
value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("natspec.js error evaluating expression: %v", err)
|
||||
}
|
||||
evalError := "Natspec evaluation failed, wrong input params"
|
||||
if value.String() == evalError {
|
||||
return "", fmt.Errorf("natspec.js error evaluating expression: wrong input params in expression '%s'", expression)
|
||||
}
|
||||
if len(value.String()) == 0 {
|
||||
return "", fmt.Errorf("natspec.js error evaluating expression")
|
||||
}
|
||||
|
||||
return value.String(), nil
|
||||
|
||||
}
|
||||
|
|
@ -1,359 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package natspec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/expanse-org/go-expanse/accounts"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/common/httpclient"
|
||||
"github.com/expanse-org/go-expanse/common/registrar"
|
||||
"github.com/expanse-org/go-expanse/core"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/eth"
|
||||
"github.com/expanse-org/go-expanse/ethdb"
|
||||
"github.com/expanse-org/go-expanse/event"
|
||||
"github.com/expanse-org/go-expanse/node"
|
||||
xe "github.com/expanse-org/go-expanse/xeth"
|
||||
)
|
||||
|
||||
const (
|
||||
testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
|
||||
testBalance = "10000000000000000000"
|
||||
testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674"
|
||||
|
||||
testFileName = "long_file_name_for_testing_registration_of_URLs_longer_than_32_bytes.content"
|
||||
|
||||
testNotice = "Register key `utils.toHex(_key)` <- content `utils.toHex(_content)`"
|
||||
|
||||
testExpNotice = "Register key 0xadd1a7d961cff0242089674ec2ef6fca671ab15e1fe80e38859fc815b98d88ab <- content 0xb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7"
|
||||
|
||||
testExpNotice2 = `About to submit transaction (NatSpec notice error: abi key does not match any method): {"params":[{"to":"%s","data": "0x31e12c20"}]}`
|
||||
|
||||
testExpNotice3 = `About to submit transaction (no NatSpec info found for contract: HashToHash: content hash not found for '0x1392c62d05b2d149e22a339c531157ae06b44d39a674cce500064b12b9aeb019'): {"params":[{"to":"%s","data": "0x300a3bbfb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066696c653a2f2f2f746573742e636f6e74656e74"}]}`
|
||||
)
|
||||
|
||||
const (
|
||||
testUserDoc = `
|
||||
{
|
||||
"methods": {
|
||||
"register(uint256,uint256)": {
|
||||
"notice": "` + testNotice + `"
|
||||
}
|
||||
},
|
||||
"invariants": [
|
||||
{ "notice": "" }
|
||||
],
|
||||
"construction": [
|
||||
{ "notice": "" }
|
||||
]
|
||||
}
|
||||
`
|
||||
testAbiDefinition = `
|
||||
[{
|
||||
"name": "register",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [{
|
||||
"name": "_key",
|
||||
"type": "uint256"
|
||||
}, {
|
||||
"name": "_content",
|
||||
"type": "uint256"
|
||||
}],
|
||||
"outputs": []
|
||||
}]
|
||||
`
|
||||
|
||||
testContractInfo = `
|
||||
{
|
||||
"userDoc": ` + testUserDoc + `,
|
||||
"abiDefinition": ` + testAbiDefinition + `
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
type testFrontend struct {
|
||||
t *testing.T
|
||||
expanse *exp.Expanse
|
||||
xeth *xe.XEth
|
||||
wait chan *big.Int
|
||||
lastConfirm string
|
||||
wantNatSpec bool
|
||||
}
|
||||
|
||||
func (self *testFrontend) AskPassword() (string, bool) {
|
||||
return "", true
|
||||
}
|
||||
|
||||
func (self *testFrontend) UnlockAccount(acc []byte) bool {
|
||||
self.expanse.AccountManager().Unlock(common.BytesToAddress(acc), "password")
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *testFrontend) ConfirmTransaction(tx string) bool {
|
||||
if self.wantNatSpec {
|
||||
client := httpclient.New("/tmp/")
|
||||
self.lastConfirm = GetNotice(self.xeth, tx, client)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func testExp(t *testing.T) (expanse *exp.Expanse, err error) {
|
||||
|
||||
tmp, err := ioutil.TempDir("", "natspec-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
addr := common.HexToAddress(testAddress)
|
||||
core.WriteGenesisBlockForTesting(db, core.GenesisAccount{addr, common.String2Big(testBalance)})
|
||||
ks := crypto.NewKeyStorePassphrase(filepath.Join(tmp, "keystore"), crypto.LightScryptN, crypto.LightScryptP)
|
||||
am := accounts.NewManager(ks)
|
||||
keyb, err := crypto.HexToECDSA(testKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
key := crypto.NewKeyFromECDSA(keyb)
|
||||
err = ks.StoreKey(key, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = am.Unlock(key.Address, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// only use minimalistic stack with no networking
|
||||
return exp.New(&node.ServiceContext{EventMux: new(event.TypeMux)}, &exp.Config{
|
||||
AccountManager: am,
|
||||
Etherbase: common.HexToAddress(testAddress),
|
||||
PowTest: true,
|
||||
TestGenesisState: db,
|
||||
GpoMinGasPrice: common.Big1,
|
||||
GpobaseCorrectionFactor: 1,
|
||||
GpoMaxGasPrice: common.Big1,
|
||||
})
|
||||
}
|
||||
|
||||
func testInit(t *testing.T) (self *testFrontend) {
|
||||
// initialise and start minimal expanse stack
|
||||
expanse, err := testExp(t)
|
||||
if err != nil {
|
||||
t.Errorf("error creating expanse: %v", err)
|
||||
return
|
||||
}
|
||||
err = expanse.Start(nil)
|
||||
if err != nil {
|
||||
t.Errorf("error starting expanse: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// mock frontend
|
||||
self = &testFrontend{t: t, ethereum: ethereum}
|
||||
self.xeth = xe.New(nil, self)
|
||||
self.wait = self.xexp.UpdateState()
|
||||
addr, _ := self.expanse.Etherbase()
|
||||
|
||||
// initialise the registry contracts
|
||||
reg := registrar.New(self.xeth)
|
||||
registrar.GlobalRegistrarAddr = "0x0"
|
||||
|
||||
var txG, txH, txU string
|
||||
txG, err = reg.SetGlobalRegistrar("", addr)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating GlobalRegistrar: %v", err)
|
||||
}
|
||||
if !processTxs(self, t, 1) {
|
||||
t.Fatalf("error mining txs")
|
||||
}
|
||||
recG := self.xexp.GetTxReceipt(common.HexToHash(txG))
|
||||
if recG == nil {
|
||||
t.Fatalf("blockchain error creating GlobalRegistrar")
|
||||
}
|
||||
registrar.GlobalRegistrarAddr = recG.ContractAddress.Hex()
|
||||
|
||||
txH, err = reg.SetHashReg("", addr)
|
||||
if err != nil {
|
||||
t.Errorf("error creating HashReg: %v", err)
|
||||
}
|
||||
if !processTxs(self, t, 1) {
|
||||
t.Errorf("error mining txs")
|
||||
}
|
||||
recH := self.xexp.GetTxReceipt(common.HexToHash(txH))
|
||||
if recH == nil {
|
||||
t.Fatalf("blockchain error creating HashReg")
|
||||
}
|
||||
registrar.HashRegAddr = recH.ContractAddress.Hex()
|
||||
|
||||
txU, err = reg.SetUrlHint("", addr)
|
||||
if err != nil {
|
||||
t.Errorf("error creating UrlHint: %v", err)
|
||||
}
|
||||
if !processTxs(self, t, 1) {
|
||||
t.Errorf("error mining txs")
|
||||
}
|
||||
recU := self.xexp.GetTxReceipt(common.HexToHash(txU))
|
||||
if recU == nil {
|
||||
t.Fatalf("blockchain error creating UrlHint")
|
||||
}
|
||||
registrar.UrlHintAddr = recU.ContractAddress.Hex()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// end to end test
|
||||
func TestNatspecE2E(t *testing.T) {
|
||||
t.Skip()
|
||||
|
||||
tf := testInit(t)
|
||||
defer tf.expanse.Stop()
|
||||
addr, _ := tf.expanse.Etherbase()
|
||||
|
||||
// create a contractInfo file (mock cloud-deployed contract metadocs)
|
||||
// incidentally this is the info for the HashReg contract itself
|
||||
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
|
||||
dochash := crypto.Keccak256Hash([]byte(testContractInfo))
|
||||
|
||||
// take the codehash for the contract we wanna test
|
||||
codeb := tf.xexp.CodeAtBytes(registrar.HashRegAddr)
|
||||
codehash := crypto.Keccak256Hash(codeb)
|
||||
|
||||
reg := registrar.New(tf.xeth)
|
||||
_, err := reg.SetHashToHash(addr, codehash, dochash)
|
||||
if err != nil {
|
||||
t.Errorf("error registering: %v", err)
|
||||
}
|
||||
_, err = reg.SetUrlToHash(addr, dochash, "file:///"+testFileName)
|
||||
if err != nil {
|
||||
t.Errorf("error registering: %v", err)
|
||||
}
|
||||
if !processTxs(tf, t, 5) {
|
||||
return
|
||||
}
|
||||
|
||||
// NatSpec info for register method of HashReg contract installed
|
||||
// now using the same transactions to check confirm messages
|
||||
|
||||
tf.wantNatSpec = true // this is set so now the backend uses natspec confirmation
|
||||
_, err = reg.SetHashToHash(addr, codehash, dochash)
|
||||
if err != nil {
|
||||
t.Errorf("error calling contract registry: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("GlobalRegistrar: %v, HashReg: %v, UrlHint: %v\n", registrar.GlobalRegistrarAddr, registrar.HashRegAddr, registrar.UrlHintAddr)
|
||||
if tf.lastConfirm != testExpNotice {
|
||||
t.Errorf("Wrong confirm message. expected\n'%v', got\n'%v'", testExpNotice, tf.lastConfirm)
|
||||
}
|
||||
|
||||
// test unknown method
|
||||
exp := fmt.Sprintf(testExpNotice2, registrar.HashRegAddr)
|
||||
_, err = reg.SetOwner(addr)
|
||||
if err != nil {
|
||||
t.Errorf("error setting owner: %v", err)
|
||||
}
|
||||
|
||||
if tf.lastConfirm != exp {
|
||||
t.Errorf("Wrong confirm message, expected\n'%v', got\n'%v'", exp, tf.lastConfirm)
|
||||
}
|
||||
|
||||
// test unknown contract
|
||||
exp = fmt.Sprintf(testExpNotice3, registrar.UrlHintAddr)
|
||||
|
||||
_, err = reg.SetUrlToHash(addr, dochash, "file:///test.content")
|
||||
if err != nil {
|
||||
t.Errorf("error registering: %v", err)
|
||||
}
|
||||
|
||||
if tf.lastConfirm != exp {
|
||||
t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func pendingTransactions(repl *testFrontend, t *testing.T) (txc int64, err error) {
|
||||
txs := repl.expanse.TxPool().GetTransactions()
|
||||
return int64(len(txs)), nil
|
||||
}
|
||||
|
||||
func processTxs(repl *testFrontend, t *testing.T, expTxc int) bool {
|
||||
var txc int64
|
||||
var err error
|
||||
for i := 0; i < 50; i++ {
|
||||
txc, err = pendingTransactions(repl, t)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error checking pending transactions: %v", err)
|
||||
return false
|
||||
}
|
||||
if expTxc < int(txc) {
|
||||
t.Errorf("too many pending transactions: expected %v, got %v", expTxc, txc)
|
||||
return false
|
||||
} else if expTxc == int(txc) {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
if int(txc) != expTxc {
|
||||
t.Errorf("incorrect number of pending transactions, expected %v, got %v", expTxc, txc)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
err = repl.expanse.StartMining(runtime.NumCPU(), "")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error mining: %v", err)
|
||||
return false
|
||||
}
|
||||
defer repl.expanse.StopMining()
|
||||
|
||||
timer := time.NewTimer(100 * time.Second)
|
||||
height := new(big.Int).Add(repl.xexp.CurrentBlock().Number(), big.NewInt(1))
|
||||
repl.wait <- height
|
||||
select {
|
||||
case <-timer.C:
|
||||
// if times out make sure the xeth loop does not block
|
||||
go func() {
|
||||
select {
|
||||
case repl.wait <- nil:
|
||||
case <-repl.wait:
|
||||
}
|
||||
}()
|
||||
case <-repl.wait:
|
||||
}
|
||||
txc, err = pendingTransactions(repl, t)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error checking pending transactions: %v", err)
|
||||
return false
|
||||
}
|
||||
if txc != 0 {
|
||||
t.Errorf("%d trasactions were not mined", txc)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
package natspec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/expanse-org/go-expanse/accounts"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/common/docserver"
|
||||
"github.com/expanse-org/go-expanse/common/registrar"
|
||||
"github.com/expanse-org/go-expanse/core"
|
||||
"github.com/expanse-org/go-expanse/core/state"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/exp"
|
||||
xe "github.com/expanse-org/go-expanse/xeth"
|
||||
)
|
||||
|
||||
const (
|
||||
testBalance = "10000000000000000000"
|
||||
|
||||
testFileName = "long_file_name_for_testing_registration_of_URLs_longer_than_32_bytes.content"
|
||||
|
||||
testNotice = "Register key `utils.toHex(_key)` <- content `utils.toHex(_content)`"
|
||||
|
||||
testExpNotice = "Register key 0xadd1a7d961cff0242089674ec2ef6fca671ab15e1fe80e38859fc815b98d88ab <- content 0xb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7"
|
||||
|
||||
testExpNotice2 = `About to submit transaction (NatSpec notice error: abi key does not match any method): {"params":[{"to":"%s","data": "0x31e12c20"}]}`
|
||||
|
||||
testExpNotice3 = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x1392c62d05b2d149e22a339c531157ae06b44d39a674cce500064b12b9aeb019'): {"params":[{"to":"%s","data": "0x300a3bbfb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066696c653a2f2f2f746573742e636f6e74656e74"}]}`
|
||||
)
|
||||
|
||||
const (
|
||||
testUserDoc = `
|
||||
{
|
||||
"methods": {
|
||||
"register(uint256,uint256)": {
|
||||
"notice": "` + testNotice + `"
|
||||
}
|
||||
},
|
||||
"invariants": [
|
||||
{ "notice": "" }
|
||||
],
|
||||
"construction": [
|
||||
{ "notice": "" }
|
||||
]
|
||||
}
|
||||
`
|
||||
testAbiDefinition = `
|
||||
[{
|
||||
"name": "register",
|
||||
"constant": false,
|
||||
"type": "function",
|
||||
"inputs": [{
|
||||
"name": "_key",
|
||||
"type": "uint256"
|
||||
}, {
|
||||
"name": "_content",
|
||||
"type": "uint256"
|
||||
}],
|
||||
"outputs": []
|
||||
}]
|
||||
`
|
||||
|
||||
testContractInfo = `
|
||||
{
|
||||
"userDoc": ` + testUserDoc + `,
|
||||
"abiDefinition": ` + testAbiDefinition + `
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
type testFrontend struct {
|
||||
t *testing.T
|
||||
expanse *exp.Expanse
|
||||
xeth *xe.XEth
|
||||
coinbase common.Address
|
||||
stateDb *state.StateDB
|
||||
txc uint64
|
||||
lastConfirm string
|
||||
wantNatSpec bool
|
||||
}
|
||||
|
||||
func (self *testFrontend) UnlockAccount(acc []byte) bool {
|
||||
self.expanse.AccountManager().Unlock(common.BytesToAddress(acc), "password")
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *testFrontend) ConfirmTransaction(tx string) bool {
|
||||
if self.wantNatSpec {
|
||||
ds := docserver.New("/tmp/")
|
||||
self.lastConfirm = GetNotice(self.xeth, tx, ds)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func testExp(t *testing.T) (expanse *exp.Expanse, err error) {
|
||||
|
||||
os.RemoveAll("/tmp/exp-natspec/")
|
||||
|
||||
err = os.MkdirAll("/tmp/exp-natspec/keystore", os.ModePerm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// create a testAddress
|
||||
ks := crypto.NewKeyStorePassphrase("/tmp/exp-natspec/keystore", crypto.LightScryptN, crypto.LightScryptP)
|
||||
am := accounts.NewManager(ks)
|
||||
testAccount, err := am.NewAccount("password")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testAddress := strings.TrimPrefix(testAccount.Address.Hex(), "0x")
|
||||
|
||||
// set up mock genesis with balance on the testAddress
|
||||
core.GenesisAccounts = []byte(`{
|
||||
"` + testAddress + `": {"balance": "` + testBalance + `"}
|
||||
}`)
|
||||
|
||||
// only use minimalistic stack with no networking
|
||||
expanse, err = exp.New(&exp.Config{
|
||||
DataDir: "/tmp/exp-natspec",
|
||||
AccountManager: am,
|
||||
MaxPeers: 0,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func testInit(t *testing.T) (self *testFrontend) {
|
||||
// initialise and start minimal expanse stack
|
||||
expanse, err := testExp(t)
|
||||
if err != nil {
|
||||
t.Errorf("error creating expanse: %v", err)
|
||||
return
|
||||
}
|
||||
err = expanse.Start()
|
||||
if err != nil {
|
||||
t.Errorf("error starting expanse: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// mock frontend
|
||||
self = &testFrontend{t: t, expanse: expanse}
|
||||
self.xeth = xe.New(expanse, self)
|
||||
|
||||
addr, _ := expanse.Etherbase()
|
||||
self.coinbase = addr
|
||||
self.stateDb = self.expanse.ChainManager().State().Copy()
|
||||
|
||||
// initialise the registry contracts
|
||||
reg := registrar.New(self.xeth)
|
||||
err = reg.SetHashReg("", addr)
|
||||
if err != nil {
|
||||
t.Errorf("error creating HashReg: %v", err)
|
||||
}
|
||||
err = reg.SetUrlHint("", addr)
|
||||
if err != nil {
|
||||
t.Errorf("error creating UrlHint: %v", err)
|
||||
}
|
||||
self.applyTxs()
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// this is needed for transaction to be applied to the state in testing
|
||||
// the heavy lifing is done in XEth.ApplyTestTxs
|
||||
// this is fragile,
|
||||
// and does process leaking since xeth loops cannot quit safely
|
||||
// should be replaced by proper mining with testDAG for easy full integration tests
|
||||
func (self *testFrontend) applyTxs() {
|
||||
self.txc, self.xeth = self.xexp.ApplyTestTxs(self.stateDb, self.coinbase, self.txc)
|
||||
return
|
||||
}
|
||||
|
||||
// end to end test
|
||||
func TestNatspecE2E(t *testing.T) {
|
||||
t.Skip()
|
||||
|
||||
tf := testInit(t)
|
||||
defer tf.expanse.Stop()
|
||||
|
||||
// create a contractInfo file (mock cloud-deployed contract metadocs)
|
||||
// incidentally this is the info for the registry contract itself
|
||||
ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
|
||||
dochash := common.BytesToHash(crypto.Sha3([]byte(testContractInfo)))
|
||||
|
||||
// take the codehash for the contract we wanna test
|
||||
// codehex := tf.xexp.CodeAt(registar.HashRegAddr)
|
||||
codeb := tf.xexp.CodeAtBytes(registrar.HashRegAddr)
|
||||
codehash := common.BytesToHash(crypto.Sha3(codeb))
|
||||
|
||||
// use resolver to register codehash->dochash->url
|
||||
// test if globalregistry works
|
||||
// registrar.HashRefAddr = "0x0"
|
||||
// registrar.UrlHintAddr = "0x0"
|
||||
reg := registrar.New(tf.xeth)
|
||||
_, err := reg.SetHashToHash(tf.coinbase, codehash, dochash)
|
||||
if err != nil {
|
||||
t.Errorf("error registering: %v", err)
|
||||
}
|
||||
_, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///"+testFileName)
|
||||
if err != nil {
|
||||
t.Errorf("error registering: %v", err)
|
||||
}
|
||||
// apply txs to the state
|
||||
tf.applyTxs()
|
||||
|
||||
// NatSpec info for register method of HashReg contract installed
|
||||
// now using the same transactions to check confirm messages
|
||||
|
||||
tf.wantNatSpec = true // this is set so now the backend uses natspec confirmation
|
||||
_, err = reg.SetHashToHash(tf.coinbase, codehash, dochash)
|
||||
if err != nil {
|
||||
t.Errorf("error calling contract registry: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("GlobalRegistrar: %v, HashReg: %v, UrlHint: %v\n", registrar.GlobalRegistrarAddr, registrar.HashRegAddr, registrar.UrlHintAddr)
|
||||
if tf.lastConfirm != testExpNotice {
|
||||
t.Errorf("Wrong confirm message. expected '%v', got '%v'", testExpNotice, tf.lastConfirm)
|
||||
}
|
||||
|
||||
// test unknown method
|
||||
exp := fmt.Sprintf(testExpNotice2, registrar.HashRegAddr)
|
||||
_, err = reg.SetOwner(tf.coinbase)
|
||||
if err != nil {
|
||||
t.Errorf("error setting owner: %v", err)
|
||||
}
|
||||
|
||||
if tf.lastConfirm != exp {
|
||||
t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
|
||||
}
|
||||
|
||||
// test unknown contract
|
||||
exp = fmt.Sprintf(testExpNotice3, registrar.UrlHintAddr)
|
||||
|
||||
_, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///test.content")
|
||||
if err != nil {
|
||||
t.Errorf("error registering: %v", err)
|
||||
}
|
||||
|
||||
if tf.lastConfirm != exp {
|
||||
t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,279 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ethreg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/expanse-org/go-expanse/accounts"
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/common/compiler"
|
||||
"github.com/expanse-org/go-expanse/common/registrar"
|
||||
"github.com/expanse-org/go-expanse/core"
|
||||
"github.com/expanse-org/go-expanse/core/state"
|
||||
"github.com/expanse-org/go-expanse/core/types"
|
||||
"github.com/expanse-org/go-expanse/core/vm"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/ethdb"
|
||||
"github.com/expanse-org/go-expanse/logger"
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
)
|
||||
|
||||
// registryAPIBackend is a backend for an Expanse Registry.
|
||||
type registryAPIBackend struct {
|
||||
config *core.ChainConfig
|
||||
bc *core.BlockChain
|
||||
chainDb ethdb.Database
|
||||
txPool *core.TxPool
|
||||
am *accounts.Manager
|
||||
}
|
||||
|
||||
// PrivateRegistarAPI offers various functions to access the Expanse registry.
|
||||
type PrivateRegistarAPI struct {
|
||||
config *core.ChainConfig
|
||||
be *registryAPIBackend
|
||||
}
|
||||
|
||||
// NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance.
|
||||
func NewPrivateRegistarAPI(config *core.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI {
|
||||
return &PrivateRegistarAPI{
|
||||
config: config,
|
||||
be: ®istryAPIBackend{
|
||||
config: config,
|
||||
bc: bc,
|
||||
chainDb: chainDb,
|
||||
txPool: txPool,
|
||||
am: am,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SetGlobalRegistrar allows clients to set the global registry for the node.
|
||||
// This method can be used to deploy a new registry. First zero out the current
|
||||
// address by calling the method with namereg = '0x0' and then call this method
|
||||
// again with '' as namereg. This will submit a transaction to the network which
|
||||
// will deploy a new registry on execution. The TX hash is returned. When called
|
||||
// with namereg '' and the current address is not zero the current global is
|
||||
// address is returned..
|
||||
func (api *PrivateRegistarAPI) SetGlobalRegistrar(namereg string, from common.Address) (string, error) {
|
||||
return registrar.New(api.be).SetGlobalRegistrar(namereg, from)
|
||||
}
|
||||
|
||||
// SetHashReg queries the registry for a hash.
|
||||
func (api *PrivateRegistarAPI) SetHashReg(hashreg string, from common.Address) (string, error) {
|
||||
return registrar.New(api.be).SetHashReg(hashreg, from)
|
||||
}
|
||||
|
||||
// SetUrlHint queries the registry for an url.
|
||||
func (api *PrivateRegistarAPI) SetUrlHint(hashreg string, from common.Address) (string, error) {
|
||||
return registrar.New(api.be).SetUrlHint(hashreg, from)
|
||||
}
|
||||
|
||||
// SaveInfo stores contract information on the local file system.
|
||||
func (api *PrivateRegistarAPI) SaveInfo(info *compiler.ContractInfo, filename string) (contenthash common.Hash, err error) {
|
||||
return compiler.SaveInfo(info, filename)
|
||||
}
|
||||
|
||||
// Register registers a new content hash in the registry.
|
||||
func (api *PrivateRegistarAPI) Register(sender common.Address, addr common.Address, contentHashHex string) (bool, error) {
|
||||
block := api.be.bc.CurrentBlock()
|
||||
state, err := state.New(block.Root(), api.be.chainDb)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
codeb := state.GetCode(addr)
|
||||
codeHash := common.BytesToHash(crypto.Keccak256(codeb))
|
||||
contentHash := common.HexToHash(contentHashHex)
|
||||
|
||||
_, err = registrar.New(api.be).SetHashToHash(sender, codeHash, contentHash)
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
// RegisterUrl registers a new url in the registry.
|
||||
func (api *PrivateRegistarAPI) RegisterUrl(sender common.Address, contentHashHex string, url string) (bool, error) {
|
||||
_, err := registrar.New(api.be).SetUrlToHash(sender, common.HexToHash(contentHashHex), url)
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
// callmsg is the message type used for call transations.
|
||||
type callmsg struct {
|
||||
from *state.StateObject
|
||||
to *common.Address
|
||||
gas, gasPrice *big.Int
|
||||
value *big.Int
|
||||
data []byte
|
||||
}
|
||||
|
||||
// accessor boilerplate to implement core.Message
|
||||
func (m callmsg) From() (common.Address, error) {
|
||||
return m.from.Address(), nil
|
||||
}
|
||||
func (m callmsg) FromFrontier() (common.Address, error) {
|
||||
return m.from.Address(), nil
|
||||
}
|
||||
func (m callmsg) Nonce() uint64 {
|
||||
return m.from.Nonce()
|
||||
}
|
||||
func (m callmsg) To() *common.Address {
|
||||
return m.to
|
||||
}
|
||||
func (m callmsg) GasPrice() *big.Int {
|
||||
return m.gasPrice
|
||||
}
|
||||
func (m callmsg) Gas() *big.Int {
|
||||
return m.gas
|
||||
}
|
||||
func (m callmsg) Value() *big.Int {
|
||||
return m.value
|
||||
}
|
||||
func (m callmsg) Data() []byte {
|
||||
return m.data
|
||||
}
|
||||
|
||||
// Call forms a transaction from the given arguments and tries to execute it on
|
||||
// a private VM with a copy of the state. Any changes are therefore only temporary
|
||||
// and not part of the actual state. This allows for local execution/queries.
|
||||
func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, string, error) {
|
||||
block := be.bc.CurrentBlock()
|
||||
statedb, err := state.New(block.Root(), be.chainDb)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var from *state.StateObject
|
||||
if len(fromStr) == 0 {
|
||||
accounts := be.am.Accounts()
|
||||
if len(accounts) == 0 {
|
||||
from = statedb.GetOrNewStateObject(common.Address{})
|
||||
} else {
|
||||
from = statedb.GetOrNewStateObject(accounts[0].Address)
|
||||
}
|
||||
} else {
|
||||
from = statedb.GetOrNewStateObject(common.HexToAddress(fromStr))
|
||||
}
|
||||
|
||||
from.SetBalance(common.MaxBig)
|
||||
|
||||
msg := callmsg{
|
||||
from: from,
|
||||
gas: common.Big(gasStr),
|
||||
gasPrice: common.Big(gasPriceStr),
|
||||
value: common.Big(valueStr),
|
||||
data: common.FromHex(dataStr),
|
||||
}
|
||||
if len(toStr) > 0 {
|
||||
addr := common.HexToAddress(toStr)
|
||||
msg.to = &addr
|
||||
}
|
||||
|
||||
if msg.gas.Cmp(big.NewInt(0)) == 0 {
|
||||
msg.gas = big.NewInt(50000000)
|
||||
}
|
||||
|
||||
if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
|
||||
msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
|
||||
}
|
||||
|
||||
header := be.bc.CurrentBlock().Header()
|
||||
vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{})
|
||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||
res, gas, err := core.ApplyMessage(vmenv, msg, gp)
|
||||
|
||||
return common.ToHex(res), gas.String(), err
|
||||
}
|
||||
|
||||
// StorageAt returns the data stores in the state for the given address and location.
|
||||
func (be *registryAPIBackend) StorageAt(addr string, storageAddr string) string {
|
||||
block := be.bc.CurrentBlock()
|
||||
state, err := state.New(block.Root(), be.chainDb)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex()
|
||||
}
|
||||
|
||||
// Transact forms a transaction from the given arguments and submits it to the
|
||||
// transactio pool for execution.
|
||||
func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
||||
if len(toStr) > 0 && toStr != "0x" && !common.IsHexAddress(toStr) {
|
||||
return "", errors.New("invalid address")
|
||||
}
|
||||
|
||||
var (
|
||||
from = common.HexToAddress(fromStr)
|
||||
to = common.HexToAddress(toStr)
|
||||
value = common.Big(valueStr)
|
||||
gas *big.Int
|
||||
price *big.Int
|
||||
data []byte
|
||||
contractCreation bool
|
||||
)
|
||||
|
||||
if len(gasStr) == 0 {
|
||||
gas = big.NewInt(90000)
|
||||
} else {
|
||||
gas = common.Big(gasStr)
|
||||
}
|
||||
|
||||
if len(gasPriceStr) == 0 {
|
||||
price = big.NewInt(10000000000000)
|
||||
} else {
|
||||
price = common.Big(gasPriceStr)
|
||||
}
|
||||
|
||||
data = common.FromHex(codeStr)
|
||||
if len(toStr) == 0 {
|
||||
contractCreation = true
|
||||
}
|
||||
|
||||
nonce := be.txPool.State().GetNonce(from)
|
||||
if len(nonceStr) != 0 {
|
||||
nonce = common.Big(nonceStr).Uint64()
|
||||
}
|
||||
|
||||
var tx *types.Transaction
|
||||
if contractCreation {
|
||||
tx = types.NewContractCreation(nonce, value, gas, price, data)
|
||||
} else {
|
||||
tx = types.NewTransaction(nonce, to, value, gas, price, data)
|
||||
}
|
||||
|
||||
signature, err := be.am.Sign(from, tx.SigHash().Bytes())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signedTx, err := tx.WithSignature(signature)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
be.txPool.SetLocal(signedTx)
|
||||
if err := be.txPool.Add(signedTx); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if contractCreation {
|
||||
addr := crypto.CreateAddress(from, nonce)
|
||||
glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
|
||||
} else {
|
||||
glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signedTx.Hash().Hex(), tx.To().Hex())
|
||||
}
|
||||
|
||||
return signedTx.Hash().Hex(), nil
|
||||
}
|
||||
|
|
@ -1,436 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package registrar
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"regexp"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/logger"
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
)
|
||||
|
||||
/*
|
||||
Registrar implements the Expanse name registrar services mapping
|
||||
- arbitrary strings to expanse addresses
|
||||
- hashes to hashes
|
||||
- hashes to arbitrary strings
|
||||
(likely will provide lookup service for all three)
|
||||
|
||||
The Registrar is used by
|
||||
* the roundtripper transport implementation of
|
||||
url schemes to resolve domain names and services that register these names
|
||||
* contract info retrieval (NatSpec).
|
||||
|
||||
The Registrar uses 3 contracts on the blockchain:
|
||||
* GlobalRegistrar: Name (string) -> Address (Owner)
|
||||
* HashReg : Key Hash (hash of domain name or contract code) -> Content Hash
|
||||
* UrlHint : Content Hash -> Url Hint
|
||||
|
||||
These contracts are (currently) not included in the genesis block.
|
||||
Each Set<X> needs to be called once on each blockchain/network once.
|
||||
|
||||
Contract addresses need to be set the first time any Registrar method is called
|
||||
in a client session.
|
||||
This is done for frontier by default, otherwise the caller needs to make sure
|
||||
the relevant environment initialised the desired contracts
|
||||
*/
|
||||
var (
|
||||
//these arnt the right ones for gexp
|
||||
GlobalRegistrarAddr = "0x6c221ca53705f3497ec90ca7b84c59ae7382fc21" // frontier
|
||||
HashRegAddr = "0x10774b55f37302de0075fdc131f63d303ae5dd9e" // frontier
|
||||
UrlHintAddr = "0x8dad0847dedb1253b6dfe616c6d2841da291dc1f" // frontier
|
||||
|
||||
zero = regexp.MustCompile("^(0x)?0*$")
|
||||
)
|
||||
|
||||
const (
|
||||
trueHex = "0000000000000000000000000000000000000000000000000000000000000001"
|
||||
falseHex = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
)
|
||||
|
||||
func abiSignature(s string) string {
|
||||
return common.ToHex(crypto.Keccak256([]byte(s))[:4])
|
||||
}
|
||||
|
||||
var (
|
||||
HashRegName = "HashReg"
|
||||
UrlHintName = "UrlHint"
|
||||
|
||||
registerContentHashAbi = abiSignature("register(uint256,uint256)")
|
||||
registerUrlAbi = abiSignature("register(uint256,uint8,uint256)")
|
||||
setOwnerAbi = abiSignature("setowner()")
|
||||
reserveAbi = abiSignature("reserve(bytes32)")
|
||||
resolveAbi = abiSignature("addr(bytes32)")
|
||||
registerAbi = abiSignature("setAddress(bytes32,address,bool)")
|
||||
addressAbiPrefix = falseHex[:24]
|
||||
)
|
||||
|
||||
// Registrar's backend is defined as an interface (implemented by xeth, but could be remote)
|
||||
type Backend interface {
|
||||
StorageAt(string, string) string
|
||||
Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error)
|
||||
Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error)
|
||||
}
|
||||
|
||||
// TODO Registrar should also just implement The Resolver and Registry interfaces
|
||||
// Simplify for now.
|
||||
type VersionedRegistrar interface {
|
||||
Resolver(*big.Int) *Registrar
|
||||
Registry() *Registrar
|
||||
}
|
||||
|
||||
type Registrar struct {
|
||||
backend Backend
|
||||
}
|
||||
|
||||
func New(b Backend) (res *Registrar) {
|
||||
res = &Registrar{b}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Registrar) SetGlobalRegistrar(namereg string, addr common.Address) (txhash string, err error) {
|
||||
if namereg != "" {
|
||||
GlobalRegistrarAddr = namereg
|
||||
return
|
||||
}
|
||||
if zero.MatchString(GlobalRegistrarAddr) {
|
||||
if (addr == common.Address{}) {
|
||||
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation not given")
|
||||
return
|
||||
} else {
|
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "800000", "", GlobalRegistrarCode)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("GlobalRegistrar address not found and sender for creation failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Registrar) SetHashReg(hashreg string, addr common.Address) (txhash string, err error) {
|
||||
if hashreg != "" {
|
||||
HashRegAddr = hashreg
|
||||
} else {
|
||||
if !zero.MatchString(HashRegAddr) {
|
||||
return
|
||||
}
|
||||
nameHex, extra := encodeName(HashRegName, 2)
|
||||
hashRegAbi := resolveAbi + nameHex + extra
|
||||
glog.V(logger.Detail).Infof("\ncall HashRegAddr %v with %v\n", GlobalRegistrarAddr, hashRegAbi)
|
||||
var res string
|
||||
res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", hashRegAbi)
|
||||
if len(res) >= 40 {
|
||||
HashRegAddr = "0x" + res[len(res)-40:len(res)]
|
||||
}
|
||||
if err != nil || zero.MatchString(HashRegAddr) {
|
||||
if (addr == common.Address{}) {
|
||||
err = fmt.Errorf("HashReg address not found and sender for creation not given")
|
||||
return
|
||||
}
|
||||
|
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "", "", HashRegCode)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("HashReg address not found and sender for creation failed: %v", err)
|
||||
}
|
||||
glog.V(logger.Detail).Infof("created HashRegAddr @ txhash %v\n", txhash)
|
||||
} else {
|
||||
glog.V(logger.Detail).Infof("HashRegAddr found at @ %v\n", HashRegAddr)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Registrar) SetUrlHint(urlhint string, addr common.Address) (txhash string, err error) {
|
||||
if urlhint != "" {
|
||||
UrlHintAddr = urlhint
|
||||
} else {
|
||||
if !zero.MatchString(UrlHintAddr) {
|
||||
return
|
||||
}
|
||||
nameHex, extra := encodeName(UrlHintName, 2)
|
||||
urlHintAbi := resolveAbi + nameHex + extra
|
||||
glog.V(logger.Detail).Infof("UrlHint address query data: %s to %s", urlHintAbi, GlobalRegistrarAddr)
|
||||
var res string
|
||||
res, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", urlHintAbi)
|
||||
if len(res) >= 40 {
|
||||
UrlHintAddr = "0x" + res[len(res)-40:len(res)]
|
||||
}
|
||||
if err != nil || zero.MatchString(UrlHintAddr) {
|
||||
if (addr == common.Address{}) {
|
||||
err = fmt.Errorf("UrlHint address not found and sender for creation not given")
|
||||
return
|
||||
}
|
||||
txhash, err = self.backend.Transact(addr.Hex(), "", "", "", "210000", "", UrlHintCode)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("UrlHint address not found and sender for creation failed: %v", err)
|
||||
}
|
||||
glog.V(logger.Detail).Infof("created UrlHint @ txhash %v\n", txhash)
|
||||
} else {
|
||||
glog.V(logger.Detail).Infof("UrlHint found @ %v\n", HashRegAddr)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReserveName(from, name) reserves name for the sender address in the globalRegistrar
|
||||
// the tx needs to be mined to take effect
|
||||
func (self *Registrar) ReserveName(address common.Address, name string) (txh string, err error) {
|
||||
if zero.MatchString(GlobalRegistrarAddr) {
|
||||
return "", fmt.Errorf("GlobalRegistrar address is not set")
|
||||
}
|
||||
nameHex, extra := encodeName(name, 2)
|
||||
abi := reserveAbi + nameHex + extra
|
||||
glog.V(logger.Detail).Infof("Reserve data: %s", abi)
|
||||
return self.backend.Transact(
|
||||
address.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
"", "", "", "",
|
||||
abi,
|
||||
)
|
||||
}
|
||||
|
||||
// SetAddressToName(from, name, addr) will set the Address to address for name
|
||||
// in the globalRegistrar using from as the sender of the transaction
|
||||
// the tx needs to be mined to take effect
|
||||
func (self *Registrar) SetAddressToName(from common.Address, name string, address common.Address) (txh string, err error) {
|
||||
if zero.MatchString(GlobalRegistrarAddr) {
|
||||
return "", fmt.Errorf("GlobalRegistrar address is not set")
|
||||
}
|
||||
|
||||
nameHex, extra := encodeName(name, 6)
|
||||
addrHex := encodeAddress(address)
|
||||
|
||||
abi := registerAbi + nameHex + addrHex + trueHex + extra
|
||||
glog.V(logger.Detail).Infof("SetAddressToName data: %s to %s ", abi, GlobalRegistrarAddr)
|
||||
|
||||
return self.backend.Transact(
|
||||
from.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
"", "", "", "",
|
||||
abi,
|
||||
)
|
||||
}
|
||||
|
||||
// NameToAddr(from, name) queries the registrar for the address on name
|
||||
func (self *Registrar) NameToAddr(from common.Address, name string) (address common.Address, err error) {
|
||||
if zero.MatchString(GlobalRegistrarAddr) {
|
||||
return address, fmt.Errorf("GlobalRegistrar address is not set")
|
||||
}
|
||||
|
||||
nameHex, extra := encodeName(name, 2)
|
||||
abi := resolveAbi + nameHex + extra
|
||||
glog.V(logger.Detail).Infof("NameToAddr data: %s", abi)
|
||||
res, _, err := self.backend.Call(
|
||||
from.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
"", "", "",
|
||||
abi,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
address = common.HexToAddress(res)
|
||||
return
|
||||
}
|
||||
|
||||
// called as first step in the registration process on HashReg
|
||||
func (self *Registrar) SetOwner(address common.Address) (txh string, err error) {
|
||||
if zero.MatchString(HashRegAddr) {
|
||||
return "", fmt.Errorf("HashReg address is not set")
|
||||
}
|
||||
return self.backend.Transact(
|
||||
address.Hex(),
|
||||
HashRegAddr,
|
||||
"", "", "", "",
|
||||
setOwnerAbi,
|
||||
)
|
||||
}
|
||||
|
||||
// registers some content hash to a key/code hash
|
||||
// e.g., the contract Info combined Json Doc's ContentHash
|
||||
// to CodeHash of a contract or hash of a domain
|
||||
func (self *Registrar) SetHashToHash(address common.Address, codehash, dochash common.Hash) (txh string, err error) {
|
||||
if zero.MatchString(HashRegAddr) {
|
||||
return "", fmt.Errorf("HashReg address is not set")
|
||||
}
|
||||
|
||||
_, err = self.SetOwner(address)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
codehex := common.Bytes2Hex(codehash[:])
|
||||
dochex := common.Bytes2Hex(dochash[:])
|
||||
|
||||
data := registerContentHashAbi + codehex + dochex
|
||||
glog.V(logger.Detail).Infof("SetHashToHash data: %s sent to %v\n", data, HashRegAddr)
|
||||
return self.backend.Transact(
|
||||
address.Hex(),
|
||||
HashRegAddr,
|
||||
"", "", "", "",
|
||||
data,
|
||||
)
|
||||
}
|
||||
|
||||
// SetUrlToHash(from, hash, url) registers a url to a content hash so that the content can be fetched
|
||||
// address is used as sender for the transaction and will be the owner of a new
|
||||
// registry entry on first time use
|
||||
// FIXME: silently doing nothing if sender is not the owner
|
||||
// note that with content addressed storage, this step is no longer necessary
|
||||
func (self *Registrar) SetUrlToHash(address common.Address, hash common.Hash, url string) (txh string, err error) {
|
||||
if zero.MatchString(UrlHintAddr) {
|
||||
return "", fmt.Errorf("UrlHint address is not set")
|
||||
}
|
||||
|
||||
hashHex := common.Bytes2Hex(hash[:])
|
||||
var urlHex string
|
||||
urlb := []byte(url)
|
||||
var cnt byte
|
||||
n := len(urlb)
|
||||
|
||||
for n > 0 {
|
||||
if n > 32 {
|
||||
n = 32
|
||||
}
|
||||
urlHex = common.Bytes2Hex(urlb[:n])
|
||||
urlb = urlb[n:]
|
||||
n = len(urlb)
|
||||
bcnt := make([]byte, 32)
|
||||
bcnt[31] = cnt
|
||||
data := registerUrlAbi +
|
||||
hashHex +
|
||||
common.Bytes2Hex(bcnt) +
|
||||
common.Bytes2Hex(common.Hex2BytesFixed(urlHex, 32))
|
||||
txh, err = self.backend.Transact(
|
||||
address.Hex(),
|
||||
UrlHintAddr,
|
||||
"", "", "", "",
|
||||
data,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cnt++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// HashToHash(key) resolves contenthash for key (a hash) using HashReg
|
||||
// resolution is costless non-transactional
|
||||
// implemented as direct retrieval from db
|
||||
func (self *Registrar) HashToHash(khash common.Hash) (chash common.Hash, err error) {
|
||||
if zero.MatchString(HashRegAddr) {
|
||||
return common.Hash{}, fmt.Errorf("HashReg address is not set")
|
||||
}
|
||||
|
||||
// look up in hashReg
|
||||
at := HashRegAddr[2:]
|
||||
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:]))
|
||||
hash := self.backend.StorageAt(at, key)
|
||||
|
||||
if hash == "0x0" || len(hash) < 3 || (hash == common.Hash{}.Hex()) {
|
||||
err = fmt.Errorf("HashToHash: content hash not found for '%v'", khash.Hex())
|
||||
return
|
||||
}
|
||||
copy(chash[:], common.Hex2BytesFixed(hash[2:], 32))
|
||||
return
|
||||
}
|
||||
|
||||
// HashToUrl(contenthash) resolves the url for contenthash using UrlHint
|
||||
// resolution is costless non-transactional
|
||||
// implemented as direct retrieval from db
|
||||
// if we use content addressed storage, this step is no longer necessary
|
||||
func (self *Registrar) HashToUrl(chash common.Hash) (uri string, err error) {
|
||||
if zero.MatchString(UrlHintAddr) {
|
||||
return "", fmt.Errorf("UrlHint address is not set")
|
||||
}
|
||||
// look up in URL reg
|
||||
var str string = " "
|
||||
var idx uint32
|
||||
for len(str) > 0 {
|
||||
mapaddr := storageMapping(storageIdx2Addr(1), chash[:])
|
||||
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx)))
|
||||
hex := self.backend.StorageAt(UrlHintAddr[2:], key)
|
||||
str = string(common.Hex2Bytes(hex[2:]))
|
||||
l := 0
|
||||
for (l < len(str)) && (str[l] == 0) {
|
||||
l++
|
||||
}
|
||||
|
||||
str = str[l:]
|
||||
uri = uri + str
|
||||
idx++
|
||||
}
|
||||
|
||||
if len(uri) == 0 {
|
||||
err = fmt.Errorf("HashToUrl: URL hint not found for '%v'", chash.Hex())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func storageIdx2Addr(varidx uint32) []byte {
|
||||
data := make([]byte, 32)
|
||||
binary.BigEndian.PutUint32(data[28:32], varidx)
|
||||
return data
|
||||
}
|
||||
|
||||
func storageMapping(addr, key []byte) []byte {
|
||||
data := make([]byte, 64)
|
||||
copy(data[0:32], key[0:32])
|
||||
copy(data[32:64], addr[0:32])
|
||||
sha := crypto.Keccak256(data)
|
||||
return sha
|
||||
}
|
||||
|
||||
func storageFixedArray(addr, idx []byte) []byte {
|
||||
var carry byte
|
||||
for i := 31; i >= 0; i-- {
|
||||
var b byte = addr[i] + idx[i] + carry
|
||||
if b < addr[i] {
|
||||
carry = 1
|
||||
} else {
|
||||
carry = 0
|
||||
}
|
||||
addr[i] = b
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
func storageAddress(addr []byte) string {
|
||||
return common.ToHex(addr)
|
||||
}
|
||||
|
||||
func encodeAddress(address common.Address) string {
|
||||
return addressAbiPrefix + address.Hex()[2:]
|
||||
}
|
||||
|
||||
func encodeName(name string, index uint8) (string, string) {
|
||||
extra := common.Bytes2Hex([]byte(name))
|
||||
if len(name) > 32 {
|
||||
return fmt.Sprintf("%064x", index), extra
|
||||
}
|
||||
return extra + falseHex[len(extra):], ""
|
||||
}
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package registrar
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
)
|
||||
|
||||
type testBackend struct {
|
||||
// contracts mock
|
||||
contracts map[string](map[string]string)
|
||||
}
|
||||
|
||||
var (
|
||||
text = "test"
|
||||
codehash = common.StringToHash("1234")
|
||||
hash = common.BytesToHash(crypto.Keccak256([]byte(text)))
|
||||
url = "bzz://bzzhash/my/path/contr.act"
|
||||
)
|
||||
|
||||
func NewTestBackend() *testBackend {
|
||||
self := &testBackend{}
|
||||
self.contracts = make(map[string](map[string]string))
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *testBackend) initHashReg() {
|
||||
self.contracts[HashRegAddr[2:]] = make(map[string]string)
|
||||
key := storageAddress(storageMapping(storageIdx2Addr(1), codehash[:]))
|
||||
self.contracts[HashRegAddr[2:]][key] = hash.Hex()
|
||||
}
|
||||
|
||||
func (self *testBackend) initUrlHint() {
|
||||
self.contracts[UrlHintAddr[2:]] = make(map[string]string)
|
||||
mapaddr := storageMapping(storageIdx2Addr(1), hash[:])
|
||||
|
||||
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0)))
|
||||
self.contracts[UrlHintAddr[2:]][key] = common.ToHex([]byte(url))
|
||||
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(1)))
|
||||
self.contracts[UrlHintAddr[2:]][key] = "0x0"
|
||||
}
|
||||
|
||||
func (self *testBackend) StorageAt(ca, sa string) (res string) {
|
||||
c := self.contracts[ca]
|
||||
if c == nil {
|
||||
return "0x0"
|
||||
}
|
||||
res = c[sa]
|
||||
return
|
||||
}
|
||||
|
||||
func (self *testBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (self *testBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
func TestSetGlobalRegistrar(t *testing.T) {
|
||||
b := NewTestBackend()
|
||||
res := New(b)
|
||||
_, err := res.SetGlobalRegistrar("addresshex", common.BigToAddress(common.Big1))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v'", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashToHash(t *testing.T) {
|
||||
b := NewTestBackend()
|
||||
res := New(b)
|
||||
|
||||
HashRegAddr = "0x0"
|
||||
got, err := res.HashToHash(codehash)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
} else {
|
||||
exp := "HashReg address is not set"
|
||||
if err.Error() != exp {
|
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
HashRegAddr = common.BigToAddress(common.Big1).Hex() //[2:]
|
||||
got, err = res.HashToHash(codehash)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
} else {
|
||||
exp := "HashToHash: content hash not found for '" + codehash.Hex() + "'"
|
||||
if err.Error() != exp {
|
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
b.initHashReg()
|
||||
got, err = res.HashToHash(codehash)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
} else {
|
||||
if got != hash {
|
||||
t.Errorf("incorrect result, expected '%v', got '%v'", hash.Hex(), got.Hex())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashToUrl(t *testing.T) {
|
||||
b := NewTestBackend()
|
||||
res := New(b)
|
||||
|
||||
UrlHintAddr = "0x0"
|
||||
got, err := res.HashToUrl(hash)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
} else {
|
||||
exp := "UrlHint address is not set"
|
||||
if err.Error() != exp {
|
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
UrlHintAddr = common.BigToAddress(common.Big2).Hex() //[2:]
|
||||
got, err = res.HashToUrl(hash)
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
} else {
|
||||
exp := "HashToUrl: URL hint not found for '" + hash.Hex() + "'"
|
||||
if err.Error() != exp {
|
||||
t.Errorf("incorrect error, expected '%v', got '%v'", exp, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
b.initUrlHint()
|
||||
got, err = res.HashToUrl(hash)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
} else {
|
||||
if got != url {
|
||||
t.Errorf("incorrect result, expected '%v', got '%s'", url, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/expanse-org/go-expanse/rlp"
|
||||
)
|
||||
|
||||
func TestNonInterfaceSlice(t *testing.T) {
|
||||
vala := []string{"value1", "value2", "value3"}
|
||||
valb := []interface{}{"value1", "value2", "value3"}
|
||||
resa := Encode(vala)
|
||||
resb := Encode(valb)
|
||||
if !bytes.Equal(resa, resb) {
|
||||
t.Errorf("expected []string & []interface{} to be equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRlpValueEncoding(t *testing.T) {
|
||||
val := EmptyValue()
|
||||
val.AppendList().Append(byte(1)).Append(byte(2)).Append(byte(3))
|
||||
val.Append("4").AppendList().Append(byte(5))
|
||||
|
||||
res, err := rlp.EncodeToBytes(val)
|
||||
if err != nil {
|
||||
t.Fatalf("encode error: %v", err)
|
||||
}
|
||||
exp := Encode([]interface{}{[]interface{}{1, 2, 3}, "4", []interface{}{5}})
|
||||
if bytes.Compare(res, exp) != 0 {
|
||||
t.Errorf("expected %x, got %x", exp, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueSlice(t *testing.T) {
|
||||
val := []interface{}{
|
||||
"value1",
|
||||
"valeu2",
|
||||
"value3",
|
||||
}
|
||||
|
||||
value := NewValue(val)
|
||||
splitVal := value.SliceFrom(1)
|
||||
|
||||
if splitVal.Len() != 2 {
|
||||
t.Error("SliceFrom: Expected len", 2, "got", splitVal.Len())
|
||||
}
|
||||
|
||||
splitVal = value.SliceTo(2)
|
||||
if splitVal.Len() != 2 {
|
||||
t.Error("SliceTo: Expected len", 2, "got", splitVal.Len())
|
||||
}
|
||||
|
||||
splitVal = value.SliceFromTo(1, 3)
|
||||
if splitVal.Len() != 2 {
|
||||
t.Error("SliceFromTo: Expected len", 2, "got", splitVal.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLargeData(t *testing.T) {
|
||||
data := make([]byte, 100000)
|
||||
enc := Encode(data)
|
||||
value := NewValueFromBytes(enc)
|
||||
if value.Len() != len(data) {
|
||||
t.Error("Expected data to be", len(data), "got", value.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestValue(t *testing.T) {
|
||||
value := NewValueFromBytes([]byte("\xcd\x83dog\x83god\x83cat\x01"))
|
||||
if value.Get(0).Str() != "dog" {
|
||||
t.Errorf("expected '%v', got '%v'", value.Get(0).Str(), "dog")
|
||||
}
|
||||
|
||||
if value.Get(3).Uint() != 1 {
|
||||
t.Errorf("expected '%v', got '%v'", value.Get(3).Uint(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
strRes := "\x83dog"
|
||||
bytes := Encode("dog")
|
||||
|
||||
str := string(bytes)
|
||||
if str != strRes {
|
||||
t.Errorf("Expected %q, got %q", strRes, str)
|
||||
}
|
||||
|
||||
sliceRes := "\xcc\x83dog\x83god\x83cat"
|
||||
strs := []interface{}{"dog", "god", "cat"}
|
||||
bytes = Encode(strs)
|
||||
slice := string(bytes)
|
||||
if slice != sliceRes {
|
||||
t.Error("Expected %q, got %q", sliceRes, slice)
|
||||
}
|
||||
|
||||
intRes := "\x82\x04\x00"
|
||||
bytes = Encode(1024)
|
||||
if string(bytes) != intRes {
|
||||
t.Errorf("Expected %q, got %q", intRes, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
single := []byte("\x01")
|
||||
b, _ := Decode(single, 0)
|
||||
|
||||
if b.(uint8) != 1 {
|
||||
t.Errorf("Expected 1, got %q", b)
|
||||
}
|
||||
|
||||
str := []byte("\x83dog")
|
||||
b, _ = Decode(str, 0)
|
||||
if bytes.Compare(b.([]byte), []byte("dog")) != 0 {
|
||||
t.Errorf("Expected dog, got %q", b)
|
||||
}
|
||||
|
||||
slice := []byte("\xcc\x83dog\x83god\x83cat")
|
||||
res := []interface{}{"dog", "god", "cat"}
|
||||
b, _ = Decode(slice, 0)
|
||||
if reflect.DeepEqual(b, res) {
|
||||
t.Errorf("Expected %q, got %q", res, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeBigInt(t *testing.T) {
|
||||
bigInt := big.NewInt(1391787038)
|
||||
encoded := Encode(bigInt)
|
||||
|
||||
value := NewValueFromBytes(encoded)
|
||||
if value.BigInt().Cmp(bigInt) != 0 {
|
||||
t.Errorf("Expected %v, got %v", bigInt, value.BigInt())
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeBytes(t *testing.T) {
|
||||
bv := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, []byte{6}})
|
||||
b, _ := rlp.EncodeToBytes(bv)
|
||||
val := NewValueFromBytes(b)
|
||||
if !bv.Cmp(val) {
|
||||
t.Errorf("Expected %#v, got %#v", bv, val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeZero(t *testing.T) {
|
||||
b, _ := rlp.EncodeToBytes(NewValue(0))
|
||||
exp := []byte{0xc0}
|
||||
if bytes.Compare(b, exp) == 0 {
|
||||
t.Error("Expected", exp, "got", b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeDecode(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
bytes := Encode([]interface{}{"dog", "god", "cat"})
|
||||
Decode(bytes, 0)
|
||||
}
|
||||
}
|
||||
428
common/value.go
428
common/value.go
|
|
@ -1,428 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/expanse-org/go-expanse/rlp"
|
||||
)
|
||||
|
||||
// Value can hold values of certain basic types and provides ways to
|
||||
// convert between types without bothering to check whether the
|
||||
// conversion is actually meaningful.
|
||||
//
|
||||
// It currently supports the following types:
|
||||
//
|
||||
// - int{,8,16,32,64}
|
||||
// - uint{,8,16,32,64}
|
||||
// - *big.Int
|
||||
// - []byte, string
|
||||
// - []interface{}
|
||||
//
|
||||
// Value is useful whenever you feel that Go's types limit your
|
||||
// ability to express yourself. In these situations, use Value and
|
||||
// forget about this strong typing nonsense.
|
||||
type Value struct{ Val interface{} }
|
||||
|
||||
func (val *Value) String() string {
|
||||
return fmt.Sprintf("%x", val.Val)
|
||||
}
|
||||
|
||||
func NewValue(val interface{}) *Value {
|
||||
t := val
|
||||
if v, ok := val.(*Value); ok {
|
||||
t = v.Val
|
||||
}
|
||||
|
||||
return &Value{Val: t}
|
||||
}
|
||||
|
||||
func (val *Value) Type() reflect.Kind {
|
||||
return reflect.TypeOf(val.Val).Kind()
|
||||
}
|
||||
|
||||
func (val *Value) IsNil() bool {
|
||||
return val.Val == nil
|
||||
}
|
||||
|
||||
func (val *Value) Len() int {
|
||||
if data, ok := val.Val.([]interface{}); ok {
|
||||
return len(data)
|
||||
}
|
||||
|
||||
return len(val.Bytes())
|
||||
}
|
||||
|
||||
func (val *Value) Uint() uint64 {
|
||||
if Val, ok := val.Val.(uint8); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(uint16); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(uint32); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(uint64); ok {
|
||||
return Val
|
||||
} else if Val, ok := val.Val.(float32); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(float64); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(int); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(uint); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.([]byte); ok {
|
||||
return new(big.Int).SetBytes(Val).Uint64()
|
||||
} else if Val, ok := val.Val.(*big.Int); ok {
|
||||
return Val.Uint64()
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (val *Value) Int() int64 {
|
||||
if Val, ok := val.Val.(int8); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(int16); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(int32); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(int64); ok {
|
||||
return Val
|
||||
} else if Val, ok := val.Val.(int); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(float32); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(float64); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.([]byte); ok {
|
||||
return new(big.Int).SetBytes(Val).Int64()
|
||||
} else if Val, ok := val.Val.(*big.Int); ok {
|
||||
return Val.Int64()
|
||||
} else if Val, ok := val.Val.(string); ok {
|
||||
n, _ := strconv.Atoi(Val)
|
||||
return int64(n)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (val *Value) Byte() byte {
|
||||
if Val, ok := val.Val.(byte); ok {
|
||||
return Val
|
||||
}
|
||||
|
||||
return 0x0
|
||||
}
|
||||
|
||||
func (val *Value) BigInt() *big.Int {
|
||||
if a, ok := val.Val.([]byte); ok {
|
||||
b := new(big.Int).SetBytes(a)
|
||||
|
||||
return b
|
||||
} else if a, ok := val.Val.(*big.Int); ok {
|
||||
return a
|
||||
} else if a, ok := val.Val.(string); ok {
|
||||
return Big(a)
|
||||
} else {
|
||||
return big.NewInt(int64(val.Uint()))
|
||||
}
|
||||
|
||||
return big.NewInt(0)
|
||||
}
|
||||
|
||||
func (val *Value) Str() string {
|
||||
if a, ok := val.Val.([]byte); ok {
|
||||
return string(a)
|
||||
} else if a, ok := val.Val.(string); ok {
|
||||
return a
|
||||
} else if a, ok := val.Val.(byte); ok {
|
||||
return string(a)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (val *Value) Bytes() []byte {
|
||||
if a, ok := val.Val.([]byte); ok {
|
||||
return a
|
||||
} else if s, ok := val.Val.(byte); ok {
|
||||
return []byte{s}
|
||||
} else if s, ok := val.Val.(string); ok {
|
||||
return []byte(s)
|
||||
} else if s, ok := val.Val.(*big.Int); ok {
|
||||
return s.Bytes()
|
||||
} else {
|
||||
return big.NewInt(val.Int()).Bytes()
|
||||
}
|
||||
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func (val *Value) Err() error {
|
||||
if err, ok := val.Val.(error); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (val *Value) Slice() []interface{} {
|
||||
if d, ok := val.Val.([]interface{}); ok {
|
||||
return d
|
||||
}
|
||||
|
||||
return []interface{}{}
|
||||
}
|
||||
|
||||
func (val *Value) SliceFrom(from int) *Value {
|
||||
slice := val.Slice()
|
||||
|
||||
return NewValue(slice[from:])
|
||||
}
|
||||
|
||||
func (val *Value) SliceTo(to int) *Value {
|
||||
slice := val.Slice()
|
||||
|
||||
return NewValue(slice[:to])
|
||||
}
|
||||
|
||||
func (val *Value) SliceFromTo(from, to int) *Value {
|
||||
slice := val.Slice()
|
||||
|
||||
return NewValue(slice[from:to])
|
||||
}
|
||||
|
||||
// TODO More type checking methods
|
||||
func (val *Value) IsSlice() bool {
|
||||
return val.Type() == reflect.Slice
|
||||
}
|
||||
|
||||
func (val *Value) IsStr() bool {
|
||||
return val.Type() == reflect.String
|
||||
}
|
||||
|
||||
func (self *Value) IsErr() bool {
|
||||
_, ok := self.Val.(error)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Special list checking function. Something is considered
|
||||
// a list if it's of type []interface{}. The list is usually
|
||||
// used in conjunction with rlp decoded streams.
|
||||
func (val *Value) IsList() bool {
|
||||
_, ok := val.Val.([]interface{})
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func (val *Value) IsEmpty() bool {
|
||||
return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0)
|
||||
}
|
||||
|
||||
// Threat the value as a slice
|
||||
func (val *Value) Get(idx int) *Value {
|
||||
if d, ok := val.Val.([]interface{}); ok {
|
||||
// Guard for oob
|
||||
if len(d) <= idx {
|
||||
return NewValue(nil)
|
||||
}
|
||||
|
||||
if idx < 0 {
|
||||
return NewValue(nil)
|
||||
}
|
||||
|
||||
return NewValue(d[idx])
|
||||
}
|
||||
|
||||
// If this wasn't a slice you probably shouldn't be using this function
|
||||
return NewValue(nil)
|
||||
}
|
||||
|
||||
func (self *Value) Copy() *Value {
|
||||
switch val := self.Val.(type) {
|
||||
case *big.Int:
|
||||
return NewValue(new(big.Int).Set(val))
|
||||
case []byte:
|
||||
return NewValue(CopyBytes(val))
|
||||
default:
|
||||
return NewValue(self.Val)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (val *Value) Cmp(o *Value) bool {
|
||||
return reflect.DeepEqual(val.Val, o.Val)
|
||||
}
|
||||
|
||||
func (self *Value) DeepCmp(o *Value) bool {
|
||||
return bytes.Compare(self.Bytes(), o.Bytes()) == 0
|
||||
}
|
||||
|
||||
func (self *Value) DecodeRLP(s *rlp.Stream) error {
|
||||
var v interface{}
|
||||
if err := s.Decode(&v); err != nil {
|
||||
return err
|
||||
}
|
||||
self.Val = v
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Value) EncodeRLP(w io.Writer) error {
|
||||
if self == nil {
|
||||
w.Write(rlp.EmptyList)
|
||||
return nil
|
||||
} else {
|
||||
return rlp.Encode(w, self.Val)
|
||||
}
|
||||
}
|
||||
|
||||
// NewValueFromBytes decodes RLP data.
|
||||
// The contained value will be nil if data contains invalid RLP.
|
||||
func NewValueFromBytes(data []byte) *Value {
|
||||
v := new(Value)
|
||||
if len(data) != 0 {
|
||||
if err := rlp.DecodeBytes(data, v); err != nil {
|
||||
v.Val = nil
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Value setters
|
||||
func NewSliceValue(s interface{}) *Value {
|
||||
list := EmptyValue()
|
||||
|
||||
if s != nil {
|
||||
if slice, ok := s.([]interface{}); ok {
|
||||
for _, val := range slice {
|
||||
list.Append(val)
|
||||
}
|
||||
} else if slice, ok := s.([]string); ok {
|
||||
for _, val := range slice {
|
||||
list.Append(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func EmptyValue() *Value {
|
||||
return NewValue([]interface{}{})
|
||||
}
|
||||
|
||||
func (val *Value) AppendList() *Value {
|
||||
list := EmptyValue()
|
||||
val.Val = append(val.Slice(), list)
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func (val *Value) Append(v interface{}) *Value {
|
||||
val.Val = append(val.Slice(), v)
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
const (
|
||||
valOpAdd = iota
|
||||
valOpDiv
|
||||
valOpMul
|
||||
valOpPow
|
||||
valOpSub
|
||||
)
|
||||
|
||||
// Math stuff
|
||||
func (self *Value) doOp(op int, other interface{}) *Value {
|
||||
left := self.BigInt()
|
||||
right := NewValue(other).BigInt()
|
||||
|
||||
switch op {
|
||||
case valOpAdd:
|
||||
self.Val = left.Add(left, right)
|
||||
case valOpDiv:
|
||||
self.Val = left.Div(left, right)
|
||||
case valOpMul:
|
||||
self.Val = left.Mul(left, right)
|
||||
case valOpPow:
|
||||
self.Val = left.Exp(left, right, Big0)
|
||||
case valOpSub:
|
||||
self.Val = left.Sub(left, right)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *Value) Add(other interface{}) *Value {
|
||||
return self.doOp(valOpAdd, other)
|
||||
}
|
||||
|
||||
func (self *Value) Sub(other interface{}) *Value {
|
||||
return self.doOp(valOpSub, other)
|
||||
}
|
||||
|
||||
func (self *Value) Div(other interface{}) *Value {
|
||||
return self.doOp(valOpDiv, other)
|
||||
}
|
||||
|
||||
func (self *Value) Mul(other interface{}) *Value {
|
||||
return self.doOp(valOpMul, other)
|
||||
}
|
||||
|
||||
func (self *Value) Pow(other interface{}) *Value {
|
||||
return self.doOp(valOpPow, other)
|
||||
}
|
||||
|
||||
type ValueIterator struct {
|
||||
value *Value
|
||||
currentValue *Value
|
||||
idx int
|
||||
}
|
||||
|
||||
func (val *Value) NewIterator() *ValueIterator {
|
||||
return &ValueIterator{value: val}
|
||||
}
|
||||
|
||||
func (it *ValueIterator) Len() int {
|
||||
return it.value.Len()
|
||||
}
|
||||
|
||||
func (it *ValueIterator) Next() bool {
|
||||
if it.idx >= it.value.Len() {
|
||||
return false
|
||||
}
|
||||
|
||||
it.currentValue = it.value.Get(it.idx)
|
||||
it.idx++
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (it *ValueIterator) Value() *Value {
|
||||
return it.currentValue
|
||||
}
|
||||
|
||||
func (it *ValueIterator) Idx() int {
|
||||
return it.idx - 1
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2015 The go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/core/state"
|
||||
)
|
||||
|
||||
var (
|
||||
jeff = common.HexToAddress("959c33de5961820567930eccce51ea715c496f85")
|
||||
vitalik = common.HexToAddress("c8158da0b567a8cc898991c2c2a073af67dc03a9")
|
||||
christoph = common.HexToAddress("7a19a893f91d5b6e2cdf941b6acbba2cbcf431ee")
|
||||
gav = common.HexToAddress("539dd9aaf45c3feb03f9c004f4098bd3268fef6b")
|
||||
)
|
||||
|
||||
// Canary will check the 0'd address of the 4 contracts above.
|
||||
// If two or more are set to anything other than a 0 the canary
|
||||
// dies a horrible death.
|
||||
func Canary(statedb *state.StateDB) bool {
|
||||
var r int
|
||||
if (statedb.GetState(jeff, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
|
||||
r++
|
||||
}
|
||||
if (statedb.GetState(gav, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
|
||||
r++
|
||||
}
|
||||
if (statedb.GetState(christoph, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
|
||||
r++
|
||||
}
|
||||
if (statedb.GetState(vitalik, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
|
||||
r++
|
||||
}
|
||||
return r > 10
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/expanse-org/go-expanse/core/vm"
|
||||
)
|
||||
|
||||
var ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
|
||||
|
||||
// ChainConfig is the core config which determines the blockchain settings.
|
||||
//
|
||||
// ChainConfig is stored in the database on a per block basis. This means
|
||||
// that any network, identified by its genesis block, can have its own
|
||||
// set of configuration options.
|
||||
type ChainConfig struct {
|
||||
HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead)
|
||||
DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork)
|
||||
DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
|
||||
|
||||
VmConfig vm.Config `json:"-"`
|
||||
}
|
||||
|
||||
// IsHomestead returns whether num is either equal to the homestead block or greater.
|
||||
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
|
||||
if c.HomesteadBlock == nil || num == nil {
|
||||
return false
|
||||
}
|
||||
return num.Cmp(c.HomesteadBlock) >= 0
|
||||
}
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/core/vm"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/params"
|
||||
|
||||
)
|
||||
|
||||
// Call executes within the given contract
|
||||
func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
|
||||
ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// CallCode executes the given address' code as the given contract address
|
||||
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
|
||||
callerAddr := caller.Address()
|
||||
ret, _, err = exec(env, caller, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
|
||||
func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
|
||||
callerAddr := caller.Address()
|
||||
originAddr := env.Origin()
|
||||
callerValue := caller.Value()
|
||||
ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, callerValue)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Create creates a new contract with the given code
|
||||
func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
|
||||
ret, address, err = exec(env, caller, nil, nil, crypto.Keccak256Hash(code), nil, code, gas, gasPrice, value)
|
||||
// Here we get an error if we run into maximum stack depth,
|
||||
// See: https://github.com/expanse-org/yellowpaper/pull/131
|
||||
// and YP definitions for CREATE instruction
|
||||
if err != nil {
|
||||
return nil, address, err
|
||||
}
|
||||
return ret, address, err
|
||||
}
|
||||
|
||||
func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
|
||||
evm := env.Vm()
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
||||
caller.ReturnGas(gas, gasPrice)
|
||||
|
||||
return nil, common.Address{}, vm.DepthError
|
||||
}
|
||||
|
||||
if !env.CanTransfer(caller.Address(), value) {
|
||||
caller.ReturnGas(gas, gasPrice)
|
||||
|
||||
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
|
||||
}
|
||||
|
||||
var createAccount bool
|
||||
if address == nil {
|
||||
// Create a new account on the state
|
||||
nonce := env.Db().GetNonce(caller.Address())
|
||||
env.Db().SetNonce(caller.Address(), nonce+1)
|
||||
addr = crypto.CreateAddress(caller.Address(), nonce)
|
||||
address = &addr
|
||||
createAccount = true
|
||||
}
|
||||
|
||||
snapshotPreTransfer := env.SnapshotDatabase()
|
||||
var (
|
||||
from = env.Db().GetAccount(caller.Address())
|
||||
to vm.Account
|
||||
)
|
||||
if createAccount {
|
||||
to = env.Db().CreateAccount(*address)
|
||||
} else {
|
||||
if !env.Db().Exist(*address) {
|
||||
to = env.Db().CreateAccount(*address)
|
||||
} else {
|
||||
to = env.Db().GetAccount(*address)
|
||||
}
|
||||
}
|
||||
env.Transfer(from, to, value)
|
||||
|
||||
// initialise a new contract and set the code that is to be used by the
|
||||
// EVM. The contract is a scoped environment for this execution context
|
||||
// only.
|
||||
contract := vm.NewContract(caller, to, value, gas, gasPrice)
|
||||
contract.SetCallCode(codeAddr, codeHash, code)
|
||||
defer contract.Finalise()
|
||||
|
||||
ret, err = evm.Run(contract, input)
|
||||
// if the contract creation ran successfully and no errors were returned
|
||||
// calculate the gas required to store the code. If the code could not
|
||||
// be stored due to not enough gas set an error and let it be handled
|
||||
// by the error checking condition below.
|
||||
if err == nil && createAccount {
|
||||
dataGas := big.NewInt(int64(len(ret)))
|
||||
dataGas.Mul(dataGas, params.CreateDataGas)
|
||||
if contract.UseGas(dataGas) {
|
||||
env.Db().SetCode(*address, ret)
|
||||
} else {
|
||||
err = vm.CodeStoreOutOfGasError
|
||||
}
|
||||
}
|
||||
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
// when we're in homestead this also counts for code storage gas errors.
|
||||
if err != nil && (env.RuleSet().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError) {
|
||||
contract.UseGas(contract.Gas)
|
||||
|
||||
env.RevertToSnapshot(snapshotPreTransfer)
|
||||
}
|
||||
|
||||
return ret, addr, err
|
||||
}
|
||||
|
||||
func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
|
||||
evm := env.Vm()
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
||||
caller.ReturnGas(gas, gasPrice)
|
||||
return nil, common.Address{}, vm.DepthError
|
||||
}
|
||||
|
||||
snapshot := env.SnapshotDatabase()
|
||||
|
||||
var to vm.Account
|
||||
if !env.Db().Exist(*toAddr) {
|
||||
to = env.Db().CreateAccount(*toAddr)
|
||||
} else {
|
||||
to = env.Db().GetAccount(*toAddr)
|
||||
}
|
||||
|
||||
// Iinitialise a new contract and make initialise the delegate values
|
||||
contract := vm.NewContract(caller, to, value, gas, gasPrice).AsDelegate()
|
||||
contract.SetCallCode(codeAddr, codeHash, code)
|
||||
defer contract.Finalise()
|
||||
|
||||
ret, err = evm.Run(contract, input)
|
||||
if err != nil {
|
||||
contract.UseGas(contract.Gas)
|
||||
|
||||
env.RevertToSnapshot(snapshot)
|
||||
}
|
||||
|
||||
return ret, addr, err
|
||||
}
|
||||
|
||||
// generic transfer method
|
||||
func Transfer(from, to vm.Account, amount *big.Int) {
|
||||
from.SubBalance(amount)
|
||||
to.AddBalance(amount)
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ package types
|
|||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
|
||||
"github.com/expanse-org/go-expanse/common/hexutil"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ import (
|
|||
)
|
||||
|
||||
// The values in those tests are from the Transaction Tests
|
||||
// at github.com/expanse-org/tests.
|
||||
|
||||
// at github.com/ethereum/tests.
|
||||
var (
|
||||
emptyTx = NewTransaction(
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
)
|
||||
|
||||
// RuleSet is an interface that defines the current rule set during the
|
||||
// execution of the EVM instructions (e.g. whether it's homestead)
|
||||
type RuleSet interface {
|
||||
IsHomestead(*big.Int) bool
|
||||
}
|
||||
|
||||
// Environment is an EVM requirement and helper which allows access to outside
|
||||
// information such as states.
|
||||
type Environment interface {
|
||||
// The current ruleset
|
||||
RuleSet() RuleSet
|
||||
// The state database
|
||||
Db() Database
|
||||
// Creates a restorable snapshot
|
||||
SnapshotDatabase() int
|
||||
// Set database to previous snapshot
|
||||
RevertToSnapshot(int)
|
||||
// Address of the original invoker (first occurrence of the VM invoker)
|
||||
Origin() common.Address
|
||||
// The block number this VM is invoked on
|
||||
BlockNumber() *big.Int
|
||||
// The n'th hash ago from this block number
|
||||
GetHash(uint64) common.Hash
|
||||
// The handler's address
|
||||
Coinbase() common.Address
|
||||
// The current time (block time)
|
||||
Time() *big.Int
|
||||
// Difficulty set on the current block
|
||||
Difficulty() *big.Int
|
||||
// The gas limit of the block
|
||||
GasLimit() *big.Int
|
||||
// Determines whether it's possible to transact
|
||||
CanTransfer(from common.Address, balance *big.Int) bool
|
||||
// Transfers amount from one account to the other
|
||||
Transfer(from, to Account, amount *big.Int)
|
||||
// Adds a LOG to the state
|
||||
AddLog(*Log)
|
||||
// Type of the VM
|
||||
Vm() Vm
|
||||
// Get the curret calling depth
|
||||
Depth() int
|
||||
// Set the current calling depth
|
||||
SetDepth(i int)
|
||||
// Call another contract
|
||||
Call(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error)
|
||||
// Take another's contract code and execute within our own context
|
||||
CallCode(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error)
|
||||
// Same as CallCode except sender and value is propagated from parent to child scope
|
||||
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
|
||||
// Create a new contract
|
||||
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
|
||||
}
|
||||
|
||||
// Vm is the basic interface for an implementation of the EVM.
|
||||
type Vm interface {
|
||||
// Run should execute the given contract with the input given in in
|
||||
// and return the contract execution return bytes or an error if it
|
||||
// failed.
|
||||
Run(c *Contract, in []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// Database is a EVM database for full state querying.
|
||||
type Database interface {
|
||||
GetAccount(common.Address) Account
|
||||
CreateAccount(common.Address) Account
|
||||
|
||||
AddBalance(common.Address, *big.Int)
|
||||
GetBalance(common.Address) *big.Int
|
||||
|
||||
GetNonce(common.Address) uint64
|
||||
SetNonce(common.Address, uint64)
|
||||
|
||||
GetCodeHash(common.Address) common.Hash
|
||||
GetCodeSize(common.Address) int
|
||||
GetCode(common.Address) []byte
|
||||
SetCode(common.Address, []byte)
|
||||
|
||||
AddRefund(*big.Int)
|
||||
GetRefund() *big.Int
|
||||
|
||||
GetState(common.Address, common.Hash) common.Hash
|
||||
SetState(common.Address, common.Hash, common.Hash)
|
||||
|
||||
Suicide(common.Address) bool
|
||||
HasSuicided(common.Address) bool
|
||||
|
||||
// Exist reports whether the given account exists in state.
|
||||
// Notably this should also return true for suicided accounts.
|
||||
Exist(common.Address) bool
|
||||
}
|
||||
|
||||
// Account represents a contract or basic expanse account.
|
||||
type Account interface {
|
||||
SubBalance(amount *big.Int)
|
||||
AddBalance(amount *big.Int)
|
||||
SetBalance(*big.Int)
|
||||
SetNonce(uint64)
|
||||
Balance() *big.Int
|
||||
Address() common.Address
|
||||
ReturnGas(*big.Int, *big.Int)
|
||||
SetCode(common.Hash, []byte)
|
||||
ForEachStorage(cb func(key, value common.Hash) bool)
|
||||
Value() *big.Int
|
||||
}
|
||||
514
core/vm/jit.go
514
core/vm/jit.go
|
|
@ -1,514 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors
|
||||
// Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
"github.com/expanse-org/go-expanse/logger"
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
"github.com/expanse-org/go-expanse/params"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
// progStatus is the type for the JIT program status.
|
||||
type progStatus int32
|
||||
|
||||
const (
|
||||
progUnknown progStatus = iota // unknown status
|
||||
progCompile // compile status
|
||||
progReady // ready for use status
|
||||
progError // error status (usually caused during compilation)
|
||||
|
||||
defaultJitMaxCache int = 64 // maximum amount of jit cached programs
|
||||
)
|
||||
|
||||
var MaxProgSize int // Max cache size for JIT programs
|
||||
|
||||
var programs *lru.Cache // lru cache for the JIT programs.
|
||||
|
||||
func init() {
|
||||
SetJITCacheSize(defaultJitMaxCache)
|
||||
}
|
||||
|
||||
// SetJITCacheSize recreates the program cache with the max given size. Setting
|
||||
// a new cache is **not** thread safe. Use with caution.
|
||||
func SetJITCacheSize(size int) {
|
||||
programs, _ = lru.New(size)
|
||||
}
|
||||
|
||||
// GetProgram returns the program by id or nil when non-existent
|
||||
func GetProgram(id common.Hash) *Program {
|
||||
if p, ok := programs.Get(id); ok {
|
||||
return p.(*Program)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenProgramStatus returns the status of the given program id
|
||||
func GetProgramStatus(id common.Hash) progStatus {
|
||||
program := GetProgram(id)
|
||||
if program != nil {
|
||||
return progStatus(atomic.LoadInt32(&program.status))
|
||||
}
|
||||
|
||||
return progUnknown
|
||||
}
|
||||
|
||||
// Program is a compiled program for the JIT VM and holds all required for
|
||||
// running a compiled JIT program.
|
||||
type Program struct {
|
||||
Id common.Hash // Id of the program
|
||||
status int32 // status should be accessed atomically
|
||||
|
||||
contract *Contract
|
||||
|
||||
instructions []programInstruction // instruction set
|
||||
mapping map[uint64]uint64 // real PC mapping to array indices
|
||||
destinations map[uint64]struct{} // cached jump destinations
|
||||
|
||||
code []byte
|
||||
}
|
||||
|
||||
// NewProgram returns a new JIT program
|
||||
func NewProgram(code []byte) *Program {
|
||||
program := &Program{
|
||||
Id: crypto.Keccak256Hash(code),
|
||||
mapping: make(map[uint64]uint64),
|
||||
destinations: make(map[uint64]struct{}),
|
||||
code: code,
|
||||
}
|
||||
|
||||
programs.Add(program.Id, program)
|
||||
return program
|
||||
}
|
||||
|
||||
func (p *Program) addInstr(op OpCode, pc uint64, fn instrFn, data *big.Int) {
|
||||
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
|
||||
// PUSH is also allowed to calculate the same price for all PUSHes
|
||||
// DUP requirements are handled elsewhere (except for the stack limit check)
|
||||
baseOp := op
|
||||
if op >= PUSH1 && op <= PUSH32 {
|
||||
baseOp = PUSH1
|
||||
}
|
||||
if op >= DUP1 && op <= DUP16 {
|
||||
baseOp = DUP1
|
||||
}
|
||||
base := _baseCheck[baseOp]
|
||||
|
||||
returns := op == RETURN || op == SUICIDE || op == STOP
|
||||
instr := instruction{op, pc, fn, data, base.gas, base.stackPop, base.stackPush, returns}
|
||||
|
||||
p.instructions = append(p.instructions, instr)
|
||||
p.mapping[pc] = uint64(len(p.instructions) - 1)
|
||||
}
|
||||
|
||||
// CompileProgram compiles the given program and return an error when it fails
|
||||
func CompileProgram(program *Program) (err error) {
|
||||
if progStatus(atomic.LoadInt32(&program.status)) == progCompile {
|
||||
return nil
|
||||
}
|
||||
atomic.StoreInt32(&program.status, int32(progCompile))
|
||||
defer func() {
|
||||
if err != nil {
|
||||
atomic.StoreInt32(&program.status, int32(progError))
|
||||
} else {
|
||||
atomic.StoreInt32(&program.status, int32(progReady))
|
||||
}
|
||||
}()
|
||||
if glog.V(logger.Debug) {
|
||||
glog.Infof("compiling %x\n", program.Id[:4])
|
||||
tstart := time.Now()
|
||||
defer func() {
|
||||
glog.Infof("compiled %x instrc: %d time: %v\n", program.Id[:4], len(program.instructions), time.Since(tstart))
|
||||
}()
|
||||
}
|
||||
|
||||
// loop thru the opcodes and "compile" in to instructions
|
||||
for pc := uint64(0); pc < uint64(len(program.code)); pc++ {
|
||||
switch op := OpCode(program.code[pc]); op {
|
||||
case ADD:
|
||||
program.addInstr(op, pc, opAdd, nil)
|
||||
case SUB:
|
||||
program.addInstr(op, pc, opSub, nil)
|
||||
case MUL:
|
||||
program.addInstr(op, pc, opMul, nil)
|
||||
case DIV:
|
||||
program.addInstr(op, pc, opDiv, nil)
|
||||
case SDIV:
|
||||
program.addInstr(op, pc, opSdiv, nil)
|
||||
case MOD:
|
||||
program.addInstr(op, pc, opMod, nil)
|
||||
case SMOD:
|
||||
program.addInstr(op, pc, opSmod, nil)
|
||||
case EXP:
|
||||
program.addInstr(op, pc, opExp, nil)
|
||||
case SIGNEXTEND:
|
||||
program.addInstr(op, pc, opSignExtend, nil)
|
||||
case NOT:
|
||||
program.addInstr(op, pc, opNot, nil)
|
||||
case LT:
|
||||
program.addInstr(op, pc, opLt, nil)
|
||||
case GT:
|
||||
program.addInstr(op, pc, opGt, nil)
|
||||
case SLT:
|
||||
program.addInstr(op, pc, opSlt, nil)
|
||||
case SGT:
|
||||
program.addInstr(op, pc, opSgt, nil)
|
||||
case EQ:
|
||||
program.addInstr(op, pc, opEq, nil)
|
||||
case ISZERO:
|
||||
program.addInstr(op, pc, opIszero, nil)
|
||||
case AND:
|
||||
program.addInstr(op, pc, opAnd, nil)
|
||||
case OR:
|
||||
program.addInstr(op, pc, opOr, nil)
|
||||
case XOR:
|
||||
program.addInstr(op, pc, opXor, nil)
|
||||
case BYTE:
|
||||
program.addInstr(op, pc, opByte, nil)
|
||||
case ADDMOD:
|
||||
program.addInstr(op, pc, opAddmod, nil)
|
||||
case MULMOD:
|
||||
program.addInstr(op, pc, opMulmod, nil)
|
||||
case SHA3:
|
||||
program.addInstr(op, pc, opSha3, nil)
|
||||
case ADDRESS:
|
||||
program.addInstr(op, pc, opAddress, nil)
|
||||
case BALANCE:
|
||||
program.addInstr(op, pc, opBalance, nil)
|
||||
case ORIGIN:
|
||||
program.addInstr(op, pc, opOrigin, nil)
|
||||
case CALLER:
|
||||
program.addInstr(op, pc, opCaller, nil)
|
||||
case CALLVALUE:
|
||||
program.addInstr(op, pc, opCallValue, nil)
|
||||
case CALLDATALOAD:
|
||||
program.addInstr(op, pc, opCalldataLoad, nil)
|
||||
case CALLDATASIZE:
|
||||
program.addInstr(op, pc, opCalldataSize, nil)
|
||||
case CALLDATACOPY:
|
||||
program.addInstr(op, pc, opCalldataCopy, nil)
|
||||
case CODESIZE:
|
||||
program.addInstr(op, pc, opCodeSize, nil)
|
||||
case EXTCODESIZE:
|
||||
program.addInstr(op, pc, opExtCodeSize, nil)
|
||||
case CODECOPY:
|
||||
program.addInstr(op, pc, opCodeCopy, nil)
|
||||
case EXTCODECOPY:
|
||||
program.addInstr(op, pc, opExtCodeCopy, nil)
|
||||
case GASPRICE:
|
||||
program.addInstr(op, pc, opGasprice, nil)
|
||||
case BLOCKHASH:
|
||||
program.addInstr(op, pc, opBlockhash, nil)
|
||||
case COINBASE:
|
||||
program.addInstr(op, pc, opCoinbase, nil)
|
||||
case TIMESTAMP:
|
||||
program.addInstr(op, pc, opTimestamp, nil)
|
||||
case NUMBER:
|
||||
program.addInstr(op, pc, opNumber, nil)
|
||||
case DIFFICULTY:
|
||||
program.addInstr(op, pc, opDifficulty, nil)
|
||||
case GASLIMIT:
|
||||
program.addInstr(op, pc, opGasLimit, nil)
|
||||
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
||||
size := uint64(op - PUSH1 + 1)
|
||||
bytes := getData([]byte(program.code), new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
|
||||
|
||||
program.addInstr(op, pc, opPush, common.Bytes2Big(bytes))
|
||||
|
||||
pc += size
|
||||
|
||||
case POP:
|
||||
program.addInstr(op, pc, opPop, nil)
|
||||
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
||||
program.addInstr(op, pc, opDup, big.NewInt(int64(op-DUP1+1)))
|
||||
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
||||
program.addInstr(op, pc, opSwap, big.NewInt(int64(op-SWAP1+2)))
|
||||
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
||||
program.addInstr(op, pc, opLog, big.NewInt(int64(op-LOG0)))
|
||||
case MLOAD:
|
||||
program.addInstr(op, pc, opMload, nil)
|
||||
case MSTORE:
|
||||
program.addInstr(op, pc, opMstore, nil)
|
||||
case MSTORE8:
|
||||
program.addInstr(op, pc, opMstore8, nil)
|
||||
case SLOAD:
|
||||
program.addInstr(op, pc, opSload, nil)
|
||||
case SSTORE:
|
||||
program.addInstr(op, pc, opSstore, nil)
|
||||
case JUMP:
|
||||
program.addInstr(op, pc, opJump, nil)
|
||||
case JUMPI:
|
||||
program.addInstr(op, pc, opJumpi, nil)
|
||||
case JUMPDEST:
|
||||
program.addInstr(op, pc, opJumpdest, nil)
|
||||
program.destinations[pc] = struct{}{}
|
||||
case PC:
|
||||
program.addInstr(op, pc, opPc, big.NewInt(int64(pc)))
|
||||
case MSIZE:
|
||||
program.addInstr(op, pc, opMsize, nil)
|
||||
case GAS:
|
||||
program.addInstr(op, pc, opGas, nil)
|
||||
case CREATE:
|
||||
program.addInstr(op, pc, opCreate, nil)
|
||||
case DELEGATECALL:
|
||||
// Instruction added regardless of homestead phase.
|
||||
// Homestead (and execution of the opcode) is checked during
|
||||
// runtime.
|
||||
program.addInstr(op, pc, opDelegateCall, nil)
|
||||
case CALL:
|
||||
program.addInstr(op, pc, opCall, nil)
|
||||
case CALLCODE:
|
||||
program.addInstr(op, pc, opCallCode, nil)
|
||||
case RETURN:
|
||||
program.addInstr(op, pc, opReturn, nil)
|
||||
case SUICIDE:
|
||||
program.addInstr(op, pc, opSuicide, nil)
|
||||
case STOP: // Stop the contract
|
||||
program.addInstr(op, pc, opStop, nil)
|
||||
default:
|
||||
program.addInstr(op, pc, nil, nil)
|
||||
}
|
||||
}
|
||||
|
||||
optimiseProgram(program)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunProgram runs the program given the environment and contract and returns an
|
||||
// error if the execution failed (non-consensus)
|
||||
func RunProgram(program *Program, env Environment, contract *Contract, input []byte) ([]byte, error) {
|
||||
return runProgram(program, 0, NewMemory(), newstack(), env, contract, input)
|
||||
}
|
||||
|
||||
func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env Environment, contract *Contract, input []byte) ([]byte, error) {
|
||||
contract.Input = input
|
||||
|
||||
var (
|
||||
pc uint64 = program.mapping[pcstart]
|
||||
instrCount = 0
|
||||
)
|
||||
|
||||
if glog.V(logger.Debug) {
|
||||
glog.Infof("running JIT program %x\n", program.Id[:4])
|
||||
tstart := time.Now()
|
||||
defer func() {
|
||||
glog.Infof("JIT program %x done. time: %v instrc: %v\n", program.Id[:4], time.Since(tstart), instrCount)
|
||||
}()
|
||||
}
|
||||
|
||||
homestead := env.RuleSet().IsHomestead(env.BlockNumber())
|
||||
for pc < uint64(len(program.instructions)) {
|
||||
instrCount++
|
||||
|
||||
instr := program.instructions[pc]
|
||||
if instr.Op() == DELEGATECALL && !homestead {
|
||||
return nil, fmt.Errorf("Invalid opcode 0x%x", instr.Op())
|
||||
}
|
||||
|
||||
ret, err := instr.do(program, &pc, env, contract, mem, stack)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if instr.halts() {
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
contract.Input = nil
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// validDest checks if the given destination is a valid one given the
|
||||
// destination table of the program
|
||||
func validDest(dests map[uint64]struct{}, dest *big.Int) bool {
|
||||
// PC cannot go beyond len(code) and certainly can't be bigger than 64bits.
|
||||
// Don't bother checking for JUMPDEST in that case.
|
||||
if dest.Cmp(bigMaxUint64) > 0 {
|
||||
return false
|
||||
}
|
||||
_, ok := dests[dest.Uint64()]
|
||||
return ok
|
||||
}
|
||||
|
||||
// jitCalculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
|
||||
// the operation. This does not reduce gas or resizes the memory.
|
||||
func jitCalculateGasAndSize(env Environment, contract *Contract, instr instruction, statedb Database, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
|
||||
var (
|
||||
gas = new(big.Int)
|
||||
newMemSize *big.Int = new(big.Int)
|
||||
)
|
||||
err := jitBaseCheck(instr, stack, gas)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// stack Check, memory resize & gas phase
|
||||
switch op := instr.op; op {
|
||||
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
||||
n := int(op - SWAP1 + 2)
|
||||
err := stack.require(n)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
gas.Set(GasFastestStep)
|
||||
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
||||
n := int(op - DUP1 + 1)
|
||||
err := stack.require(n)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
gas.Set(GasFastestStep)
|
||||
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
||||
n := int(op - LOG0)
|
||||
err := stack.require(n + 2)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
||||
|
||||
add := new(big.Int)
|
||||
gas.Add(gas, params.LogGas)
|
||||
gas.Add(gas, add.Mul(big.NewInt(int64(n)), params.LogTopicGas))
|
||||
gas.Add(gas, add.Mul(mSize, params.LogDataGas))
|
||||
|
||||
newMemSize = calcMemSize(mStart, mSize)
|
||||
case EXP:
|
||||
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
|
||||
case SSTORE:
|
||||
err := stack.require(2)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var g *big.Int
|
||||
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
||||
val := statedb.GetState(contract.Address(), common.BigToHash(x))
|
||||
|
||||
// This checks for 3 scenario's and calculates gas accordingly
|
||||
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
||||
// 2. From a non-zero value address to a zero-value address (DELETE)
|
||||
// 3. From a non-zero to a non-zero (CHANGE)
|
||||
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
|
||||
g = params.SstoreSetGas
|
||||
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
|
||||
statedb.AddRefund(params.SstoreRefundGas)
|
||||
|
||||
g = params.SstoreClearGas
|
||||
} else {
|
||||
g = params.SstoreClearGas
|
||||
}
|
||||
gas.Set(g)
|
||||
case SUICIDE:
|
||||
if !statedb.HasSuicided(contract.Address()) {
|
||||
statedb.AddRefund(params.SuicideRefundGas)
|
||||
}
|
||||
case MLOAD:
|
||||
newMemSize = calcMemSize(stack.peek(), u256(32))
|
||||
case MSTORE8:
|
||||
newMemSize = calcMemSize(stack.peek(), u256(1))
|
||||
case MSTORE:
|
||||
newMemSize = calcMemSize(stack.peek(), u256(32))
|
||||
case RETURN:
|
||||
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
|
||||
case SHA3:
|
||||
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
|
||||
|
||||
words := toWordSize(stack.data[stack.len()-2])
|
||||
gas.Add(gas, words.Mul(words, params.Sha3WordGas))
|
||||
case CALLDATACOPY:
|
||||
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
|
||||
|
||||
words := toWordSize(stack.data[stack.len()-3])
|
||||
gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||
case CODECOPY:
|
||||
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
|
||||
|
||||
words := toWordSize(stack.data[stack.len()-3])
|
||||
gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||
case EXTCODECOPY:
|
||||
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
|
||||
|
||||
words := toWordSize(stack.data[stack.len()-4])
|
||||
gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||
|
||||
case CREATE:
|
||||
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
|
||||
case CALL, CALLCODE:
|
||||
gas.Add(gas, stack.data[stack.len()-1])
|
||||
|
||||
if op == CALL {
|
||||
if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) {
|
||||
gas.Add(gas, params.CallNewAccountGas)
|
||||
}
|
||||
}
|
||||
|
||||
if len(stack.data[stack.len()-3].Bytes()) > 0 {
|
||||
gas.Add(gas, params.CallValueTransferGas)
|
||||
}
|
||||
|
||||
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
|
||||
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
|
||||
|
||||
newMemSize = common.BigMax(x, y)
|
||||
case DELEGATECALL:
|
||||
gas.Add(gas, stack.data[stack.len()-1])
|
||||
|
||||
x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6])
|
||||
y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4])
|
||||
|
||||
newMemSize = common.BigMax(x, y)
|
||||
}
|
||||
quadMemGas(mem, newMemSize, gas)
|
||||
|
||||
return newMemSize, gas, nil
|
||||
}
|
||||
|
||||
// jitBaseCheck is the same as baseCheck except it doesn't do the look up in the
|
||||
// gas table. This is done during compilation instead.
|
||||
func jitBaseCheck(instr instruction, stack *stack, gas *big.Int) error {
|
||||
err := stack.require(instr.spop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if instr.spush > 0 && stack.len()-instr.spop+instr.spush > int(params.StackLimit.Int64()) {
|
||||
return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64())
|
||||
}
|
||||
|
||||
// nil on gas means no base calculation
|
||||
if instr.gas == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
gas.Add(gas, instr.gas)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/expanse-org/go-expanse/logger"
|
||||
"github.com/expanse-org/go-expanse/logger/glog"
|
||||
)
|
||||
|
||||
// optimeProgram optimises a JIT program creating segments out of program
|
||||
// instructions. Currently covered are multi-pushes and static jumps
|
||||
func optimiseProgram(program *Program) {
|
||||
var load []instruction
|
||||
|
||||
var (
|
||||
statsJump = 0
|
||||
statsPush = 0
|
||||
)
|
||||
|
||||
if glog.V(logger.Debug) {
|
||||
glog.Infof("optimising %x\n", program.Id[:4])
|
||||
tstart := time.Now()
|
||||
defer func() {
|
||||
glog.Infof("optimised %x done in %v with JMP: %d PSH: %d\n", program.Id[:4], time.Since(tstart), statsJump, statsPush)
|
||||
}()
|
||||
}
|
||||
|
||||
/*
|
||||
code := Parse(program.code)
|
||||
for _, test := range [][]OpCode{
|
||||
[]OpCode{PUSH, PUSH, ADD},
|
||||
[]OpCode{PUSH, PUSH, SUB},
|
||||
[]OpCode{PUSH, PUSH, MUL},
|
||||
[]OpCode{PUSH, PUSH, DIV},
|
||||
} {
|
||||
matchCount := 0
|
||||
MatchFn(code, test, func(i int) bool {
|
||||
matchCount++
|
||||
return true
|
||||
})
|
||||
fmt.Printf("found %d match count on: %v\n", matchCount, test)
|
||||
}
|
||||
*/
|
||||
|
||||
for i := 0; i < len(program.instructions); i++ {
|
||||
instr := program.instructions[i].(instruction)
|
||||
|
||||
switch {
|
||||
case instr.op.IsPush():
|
||||
load = append(load, instr)
|
||||
case instr.op.IsStaticJump():
|
||||
if len(load) == 0 {
|
||||
continue
|
||||
}
|
||||
// if the push load is greater than 1, finalise that
|
||||
// segment first
|
||||
if len(load) > 2 {
|
||||
seg, size := makePushSeg(load[:len(load)-1])
|
||||
program.instructions[i-size-1] = seg
|
||||
statsPush++
|
||||
}
|
||||
// create a segment consisting of a pre determined
|
||||
// jump, destination and validity.
|
||||
seg := makeStaticJumpSeg(load[len(load)-1].data, program)
|
||||
program.instructions[i-1] = seg
|
||||
statsJump++
|
||||
|
||||
load = nil
|
||||
default:
|
||||
// create a new N pushes segment
|
||||
if len(load) > 1 {
|
||||
seg, size := makePushSeg(load)
|
||||
program.instructions[i-size] = seg
|
||||
statsPush++
|
||||
}
|
||||
load = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// makePushSeg creates a new push segment from N amount of push instructions
|
||||
func makePushSeg(instrs []instruction) (pushSeg, int) {
|
||||
var (
|
||||
data []*big.Int
|
||||
gas = new(big.Int)
|
||||
)
|
||||
|
||||
for _, instr := range instrs {
|
||||
data = append(data, instr.data)
|
||||
gas.Add(gas, instr.gas)
|
||||
}
|
||||
|
||||
return pushSeg{data, gas}, len(instrs)
|
||||
}
|
||||
|
||||
// makeStaticJumpSeg creates a new static jump segment from a predefined
|
||||
// destination (PUSH, JUMP).
|
||||
func makeStaticJumpSeg(to *big.Int, program *Program) jumpSeg {
|
||||
gas := new(big.Int)
|
||||
gas.Add(gas, _baseCheck[PUSH1].gas)
|
||||
gas.Add(gas, _baseCheck[JUMP].gas)
|
||||
|
||||
contract := &Contract{Code: program.code}
|
||||
pos, err := jump(program.mapping, program.destinations, contract, to)
|
||||
return jumpSeg{pos, err, gas}
|
||||
}
|
||||
|
|
@ -1,219 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors
|
||||
// Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/crypto"
|
||||
)
|
||||
|
||||
const maxRun = 1000
|
||||
|
||||
func TestSegmenting(t *testing.T) {
|
||||
prog := NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, 0x0})
|
||||
err := CompileProgram(prog)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if instr, ok := prog.instructions[0].(pushSeg); ok {
|
||||
if len(instr.data) != 2 {
|
||||
t.Error("expected 2 element width pushSegment, got", len(instr.data))
|
||||
}
|
||||
} else {
|
||||
t.Errorf("expected instr[0] to be a pushSeg, got %T", prog.instructions[0])
|
||||
}
|
||||
|
||||
prog = NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(JUMP)})
|
||||
err = CompileProgram(prog)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := prog.instructions[1].(jumpSeg); ok {
|
||||
} else {
|
||||
t.Errorf("expected instr[1] to be jumpSeg, got %T", prog.instructions[1])
|
||||
}
|
||||
|
||||
prog = NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(JUMP)})
|
||||
err = CompileProgram(prog)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if instr, ok := prog.instructions[0].(pushSeg); ok {
|
||||
if len(instr.data) != 2 {
|
||||
t.Error("expected 2 element width pushSegment, got", len(instr.data))
|
||||
}
|
||||
} else {
|
||||
t.Errorf("expected instr[0] to be a pushSeg, got %T", prog.instructions[0])
|
||||
}
|
||||
if _, ok := prog.instructions[2].(jumpSeg); ok {
|
||||
} else {
|
||||
t.Errorf("expected instr[1] to be jumpSeg, got %T", prog.instructions[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompiling(t *testing.T) {
|
||||
prog := NewProgram([]byte{0x60, 0x10})
|
||||
err := CompileProgram(prog)
|
||||
if err != nil {
|
||||
t.Error("didn't expect compile error")
|
||||
}
|
||||
|
||||
if len(prog.instructions) != 1 {
|
||||
t.Error("expected 1 compiled instruction, got", len(prog.instructions))
|
||||
}
|
||||
}
|
||||
|
||||
func TestResetInput(t *testing.T) {
|
||||
var sender account
|
||||
|
||||
env := NewEnv(false, true)
|
||||
contract := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0))
|
||||
contract.CodeAddr = &common.Address{}
|
||||
|
||||
program := NewProgram([]byte{})
|
||||
RunProgram(program, env, contract, []byte{0xbe, 0xef})
|
||||
if contract.Input != nil {
|
||||
t.Errorf("expected input to be nil, got %x", contract.Input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPcMappingToInstruction(t *testing.T) {
|
||||
program := NewProgram([]byte{byte(PUSH2), 0xbe, 0xef, byte(ADD)})
|
||||
CompileProgram(program)
|
||||
if program.mapping[3] != 1 {
|
||||
t.Error("expected mapping PC 4 to me instr no. 2, got", program.mapping[4])
|
||||
}
|
||||
}
|
||||
|
||||
var benchmarks = map[string]vmBench{
|
||||
"pushes": vmBench{
|
||||
false, false, false,
|
||||
common.Hex2Bytes("600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01"), nil,
|
||||
},
|
||||
}
|
||||
|
||||
func BenchmarkPushes(b *testing.B) {
|
||||
runVmBench(benchmarks["pushes"], b)
|
||||
}
|
||||
|
||||
type vmBench struct {
|
||||
precompile bool // compile prior to executing
|
||||
nojit bool // ignore jit (sets DisbaleJit = true
|
||||
forcejit bool // forces the jit, precompile is ignored
|
||||
|
||||
code []byte
|
||||
input []byte
|
||||
}
|
||||
|
||||
type account struct{}
|
||||
|
||||
func (account) SubBalance(amount *big.Int) {}
|
||||
func (account) AddBalance(amount *big.Int) {}
|
||||
func (account) SetAddress(common.Address) {}
|
||||
func (account) Value() *big.Int { return nil }
|
||||
func (account) SetBalance(*big.Int) {}
|
||||
func (account) SetNonce(uint64) {}
|
||||
func (account) Balance() *big.Int { return nil }
|
||||
func (account) Address() common.Address { return common.Address{} }
|
||||
func (account) ReturnGas(*big.Int, *big.Int) {}
|
||||
func (account) SetCode(common.Hash, []byte) {}
|
||||
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
|
||||
|
||||
func runVmBench(test vmBench, b *testing.B) {
|
||||
var sender account
|
||||
|
||||
if test.precompile && !test.forcejit {
|
||||
NewProgram(test.code)
|
||||
}
|
||||
env := NewEnv(test.nojit, test.forcejit)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
context := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0))
|
||||
context.Code = test.code
|
||||
context.CodeAddr = &common.Address{}
|
||||
_, err := env.Vm().Run(context, test.input)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
b.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Env struct {
|
||||
gasLimit *big.Int
|
||||
depth int
|
||||
evm *EVM
|
||||
}
|
||||
|
||||
func NewEnv(noJit, forceJit bool) *Env {
|
||||
env := &Env{gasLimit: big.NewInt(10000), depth: 0}
|
||||
env.evm = New(env, Config{
|
||||
EnableJit: !noJit,
|
||||
ForceJit: forceJit,
|
||||
})
|
||||
return env
|
||||
}
|
||||
|
||||
func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
|
||||
func (self *Env) Vm() Vm { return self.evm }
|
||||
func (self *Env) Origin() common.Address { return common.Address{} }
|
||||
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
|
||||
func (self *Env) AddStructLog(log StructLog) {
|
||||
}
|
||||
func (self *Env) StructLogs() []StructLog {
|
||||
return nil
|
||||
}
|
||||
|
||||
//func (self *Env) PrevHash() []byte { return self.parent }
|
||||
func (self *Env) Coinbase() common.Address { return common.Address{} }
|
||||
func (self *Env) SnapshotDatabase() int { return 0 }
|
||||
func (self *Env) RevertToSnapshot(int) {}
|
||||
func (self *Env) Time() *big.Int { return big.NewInt(time.Now().Unix()) }
|
||||
func (self *Env) Difficulty() *big.Int { return big.NewInt(0) }
|
||||
func (self *Env) Db() Database { return nil }
|
||||
func (self *Env) GasLimit() *big.Int { return self.gasLimit }
|
||||
func (self *Env) VmType() Type { return StdVmTy }
|
||||
func (self *Env) GetHash(n uint64) common.Hash {
|
||||
return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String())))
|
||||
}
|
||||
func (self *Env) AddLog(log *Log) {
|
||||
}
|
||||
func (self *Env) Depth() int { return self.depth }
|
||||
func (self *Env) SetDepth(i int) { self.depth = i }
|
||||
func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool {
|
||||
return true
|
||||
}
|
||||
func (self *Env) Transfer(from, to Account, amount *big.Int) {}
|
||||
func (self *Env) Call(caller ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (self *Env) CallCode(caller ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (self *Env) Create(caller ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
|
||||
return nil, common.Address{}, nil
|
||||
}
|
||||
func (self *Env) DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors && Copyright 2015 go-expanse Authors
|
||||
// This file is part of the go-expanse library.
|
||||
//
|
||||
// The go-expanse library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-expanse library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-expanse library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package vm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/expanse-org/go-expanse/common"
|
||||
"github.com/expanse-org/go-expanse/rlp"
|
||||
)
|
||||
|
||||
type Log struct {
|
||||
// Consensus fields
|
||||
Address common.Address
|
||||
Topics []common.Hash
|
||||
Data []byte
|
||||
|
||||
// Derived fields (don't reorder!)
|
||||
BlockNumber uint64
|
||||
TxHash common.Hash
|
||||
TxIndex uint
|
||||
BlockHash common.Hash
|
||||
Index uint
|
||||
}
|
||||
|
||||
func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *Log {
|
||||
return &Log{Address: address, Topics: topics, Data: data, BlockNumber: number}
|
||||
}
|
||||
|
||||
func (l *Log) EncodeRLP(w io.Writer) error {
|
||||
return rlp.Encode(w, []interface{}{l.Address, l.Topics, l.Data})
|
||||
}
|
||||
|
||||
func (l *Log) DecodeRLP(s *rlp.Stream) error {
|
||||
var log struct {
|
||||
Address common.Address
|
||||
Topics []common.Hash
|
||||
Data []byte
|
||||
}
|
||||
if err := s.Decode(&log); err != nil {
|
||||
return err
|
||||
}
|
||||
l.Address, l.Topics, l.Data = log.Address, log.Topics, log.Data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Log) String() string {
|
||||
return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, l.Address, l.Topics, l.Data, l.TxHash, l.TxIndex, l.BlockHash, l.Index)
|
||||
}
|
||||
|
||||
func (r *Log) MarshalJSON() ([]byte, error) {
|
||||
fields := map[string]interface{}{
|
||||
"address": r.Address,
|
||||
"data": fmt.Sprintf("%#x", r.Data),
|
||||
"blockNumber": fmt.Sprintf("%#x", r.BlockNumber),
|
||||
"logIndex": fmt.Sprintf("%#x", r.Index),
|
||||
"blockHash": r.BlockHash,
|
||||
"transactionHash": r.TxHash,
|
||||
"transactionIndex": fmt.Sprintf("%#x", r.TxIndex),
|
||||
"topics": r.Topics,
|
||||
}
|
||||
|
||||
return json.Marshal(fields)
|
||||
}
|
||||
|
||||
type Logs []*Log
|
||||
|
||||
// LogForStorage is a wrapper around a Log that flattens and parses the entire
|
||||
// content of a log, as opposed to only the consensus fields originally (by hiding
|
||||
// the rlp interface methods).
|
||||
type LogForStorage Log
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue