mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
consenus/eccpow: add algorithm
This commit is contained in:
parent
8094fc1d87
commit
4fa7eb674e
2 changed files with 606 additions and 0 deletions
516
consensus/eccpow/algorithm.go
Normal file
516
consensus/eccpow/algorithm.go
Normal file
|
|
@ -0,0 +1,516 @@
|
||||||
|
package eccpow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"hash"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cryptoecc/ETH-ECC/consensus"
|
||||||
|
"github.com/cryptoecc/ETH-ECC/core/types"
|
||||||
|
"github.com/cryptoecc/ETH-ECC/crypto"
|
||||||
|
"github.com/cryptoecc/ETH-ECC/log"
|
||||||
|
"github.com/cryptoecc/ETH-ECC/metrics"
|
||||||
|
"github.com/cryptoecc/ETH-ECC/rpc"
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ECC struct {
|
||||||
|
config Config
|
||||||
|
|
||||||
|
// Mining related fields
|
||||||
|
rand *rand.Rand // Properly seeded random source for nonces
|
||||||
|
threads int // Number of threads to mine on if mining
|
||||||
|
update chan struct{} // Notification channel to update mining parameters
|
||||||
|
hashrate metrics.Meter // Meter tracking the average hashrate
|
||||||
|
remote *remoteSealer
|
||||||
|
|
||||||
|
// Remote sealer related fields
|
||||||
|
workCh chan *sealTask // Notification channel to push new work and relative result channel to remote sealer
|
||||||
|
fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work
|
||||||
|
submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result
|
||||||
|
fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer.
|
||||||
|
submitRateCh chan *hashrate // Channel used for remote sealer to submit their mining hashrate
|
||||||
|
|
||||||
|
shared *ECC // Shared PoW verifier to avoid cache regeneration
|
||||||
|
fakeFail uint64 // Block number which fails PoW check even in fake mode
|
||||||
|
fakeDelay time.Duration // Time delay to sleep for before returning from verify
|
||||||
|
|
||||||
|
lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields
|
||||||
|
closeOnce sync.Once // Ensures exit channel will not be closed twice.
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mode uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
epochLength = 30000 // Blocks per epoch
|
||||||
|
ModeNormal Mode = iota
|
||||||
|
ModeShared
|
||||||
|
ModeTest
|
||||||
|
ModeFake
|
||||||
|
ModeFullFake
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config are the configuration parameters of the ethash.
|
||||||
|
type Config struct {
|
||||||
|
PowMode Mode
|
||||||
|
// When set, notifications sent by the remote sealer will
|
||||||
|
// be block header JSON objects instead of work package arrays.
|
||||||
|
NotifyFull bool
|
||||||
|
Log log.Logger `toml:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasher is a repetitive hasher allowing the same hash data structures to be
|
||||||
|
// reused between hash runs instead of requiring new ones to be created.
|
||||||
|
//var hasher func(dest []byte, data []byte)
|
||||||
|
|
||||||
|
var (
|
||||||
|
two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
|
||||||
|
|
||||||
|
// sharedECC is a full instance that can be shared between multiple users.
|
||||||
|
sharedECC *ECC
|
||||||
|
|
||||||
|
// algorithmRevision is the data structure version used for file naming.
|
||||||
|
algorithmRevision = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
sharedConfig := Config{
|
||||||
|
PowMode: ModeNormal,
|
||||||
|
}
|
||||||
|
sharedECC = New(sharedConfig, nil, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
type verifyParameters struct {
|
||||||
|
n uint64
|
||||||
|
m uint64
|
||||||
|
wc uint64
|
||||||
|
wr uint64
|
||||||
|
seed uint64
|
||||||
|
outputWord []uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
//const cross_err = 0.01
|
||||||
|
|
||||||
|
//type (
|
||||||
|
// intMatrix [][]int
|
||||||
|
// floatMatrix [][]float64
|
||||||
|
//)
|
||||||
|
|
||||||
|
//RunOptimizedConcurrencyLDPC use goroutine for mining block
|
||||||
|
func RunOptimizedConcurrencyLDPC(header *types.Header, hash []byte) (bool, []int, []int, uint64, []byte) {
|
||||||
|
//Need to set difficulty before running LDPC
|
||||||
|
// Number of goroutines : 500, Number of attempts : 50000 Not bad
|
||||||
|
|
||||||
|
var LDPCNonce uint64
|
||||||
|
var hashVector []int
|
||||||
|
var outputWord []int
|
||||||
|
var digest []byte
|
||||||
|
var flag bool
|
||||||
|
|
||||||
|
//var wg sync.WaitGroup
|
||||||
|
//var outerLoopSignal = make(chan struct{})
|
||||||
|
//var innerLoopSignal = make(chan struct{})
|
||||||
|
//var goRoutineSignal = make(chan struct{})
|
||||||
|
|
||||||
|
parameters, _ := setParameters(header)
|
||||||
|
H := generateH(parameters)
|
||||||
|
colInRow, rowInCol := generateQ(parameters, H)
|
||||||
|
|
||||||
|
for i := 0; i < 64; i++ {
|
||||||
|
var goRoutineHashVector []int
|
||||||
|
var goRoutineOutputWord []int
|
||||||
|
goRoutineNonce := generateRandomNonce()
|
||||||
|
seed := make([]byte, 40)
|
||||||
|
copy(seed, hash)
|
||||||
|
binary.LittleEndian.PutUint64(seed[32:], goRoutineNonce)
|
||||||
|
seed = crypto.Keccak512(seed)
|
||||||
|
//fmt.Printf("nonce: %v\n", seed)
|
||||||
|
|
||||||
|
goRoutineHashVector = generateHv(parameters, seed)
|
||||||
|
goRoutineHashVector, goRoutineOutputWord, _ = OptimizedDecoding(parameters, goRoutineHashVector, H, rowInCol, colInRow)
|
||||||
|
|
||||||
|
flag, _ = MakeDecision(header, colInRow, goRoutineOutputWord)
|
||||||
|
|
||||||
|
if flag {
|
||||||
|
hashVector = goRoutineHashVector
|
||||||
|
outputWord = goRoutineOutputWord
|
||||||
|
LDPCNonce = goRoutineNonce
|
||||||
|
digest = seed
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag, hashVector, outputWord, LDPCNonce, digest
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunOptimizedConcurrencyLDPC_Seoul(header *types.Header, hash []byte) (bool, []int, []int, uint64, []byte) {
|
||||||
|
//Need to set difficulty before running LDPC
|
||||||
|
// Number of goroutines : 500, Number of attempts : 50000 Not bad
|
||||||
|
|
||||||
|
var LDPCNonce uint64
|
||||||
|
var hashVector []int
|
||||||
|
var outputWord []int
|
||||||
|
var digest []byte
|
||||||
|
var flag bool
|
||||||
|
|
||||||
|
//var wg sync.WaitGroup
|
||||||
|
//var outerLoopSignal = make(chan struct{})
|
||||||
|
//var innerLoopSignal = make(chan struct{})
|
||||||
|
//var goRoutineSignal = make(chan struct{})
|
||||||
|
|
||||||
|
parameters, _ := setParameters_Seoul(header)
|
||||||
|
H := generateH(parameters)
|
||||||
|
colInRow, rowInCol := generateQ(parameters, H)
|
||||||
|
|
||||||
|
for i := 0; i < 64; i++ {
|
||||||
|
var goRoutineHashVector []int
|
||||||
|
var goRoutineOutputWord []int
|
||||||
|
goRoutineNonce := generateRandomNonce()
|
||||||
|
seed := make([]byte, 40)
|
||||||
|
copy(seed, hash)
|
||||||
|
binary.LittleEndian.PutUint64(seed[32:], goRoutineNonce)
|
||||||
|
seed = crypto.Keccak512(seed)
|
||||||
|
//fmt.Printf("nonce: %v\n", seed)
|
||||||
|
|
||||||
|
goRoutineHashVector = generateHv(parameters, seed)
|
||||||
|
goRoutineHashVector, goRoutineOutputWord, _ = OptimizedDecodingSeoul(parameters, goRoutineHashVector, H, rowInCol, colInRow)
|
||||||
|
|
||||||
|
flag, _ = MakeDecision_Seoul(header, colInRow, goRoutineOutputWord)
|
||||||
|
|
||||||
|
if flag {
|
||||||
|
hashVector = goRoutineHashVector
|
||||||
|
outputWord = goRoutineOutputWord
|
||||||
|
LDPCNonce = goRoutineNonce
|
||||||
|
digest = seed
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag, hashVector, outputWord, LDPCNonce, digest
|
||||||
|
}
|
||||||
|
|
||||||
|
//MakeDecision check outputWord is valid or not using colInRow
|
||||||
|
func MakeDecision(header *types.Header, colInRow [][]int, outputWord []int) (bool, int) {
|
||||||
|
parameters, difficultyLevel := setParameters(header)
|
||||||
|
for i := 0; i < parameters.m; i++ {
|
||||||
|
sum := 0
|
||||||
|
for j := 0; j < parameters.wr; j++ {
|
||||||
|
// fmt.Printf("i : %d, j : %d, m : %d, wr : %d \n", i, j, m, wr)
|
||||||
|
sum = sum + outputWord[colInRow[j][i]]
|
||||||
|
}
|
||||||
|
if sum%2 == 1 {
|
||||||
|
return false, -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var numOfOnes int
|
||||||
|
for _, val := range outputWord {
|
||||||
|
numOfOnes += val
|
||||||
|
}
|
||||||
|
|
||||||
|
if numOfOnes >= Table[difficultyLevel].decisionFrom &&
|
||||||
|
numOfOnes <= Table[difficultyLevel].decisionTo &&
|
||||||
|
numOfOnes%Table[difficultyLevel].decisionStep == 0 {
|
||||||
|
//fmt.Printf("hamming weight: %v\n", numOfOnes)
|
||||||
|
return true, numOfOnes
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, numOfOnes
|
||||||
|
}
|
||||||
|
|
||||||
|
//MakeDecision check outputWord is valid or not using colInRow
|
||||||
|
func MakeDecision_Seoul(header *types.Header, colInRow [][]int, outputWord []int) (bool, int) {
|
||||||
|
parameters, _ := setParameters_Seoul(header)
|
||||||
|
for i := 0; i < parameters.m; i++ {
|
||||||
|
sum := 0
|
||||||
|
for j := 0; j < parameters.wr; j++ {
|
||||||
|
// fmt.Printf("i : %d, j : %d, m : %d, wr : %d \n", i, j, m, wr)
|
||||||
|
sum = sum + outputWord[colInRow[j][i]]
|
||||||
|
}
|
||||||
|
if sum%2 == 1 {
|
||||||
|
return false, -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var numOfOnes int
|
||||||
|
for _, val := range outputWord {
|
||||||
|
numOfOnes += val
|
||||||
|
}
|
||||||
|
|
||||||
|
if numOfOnes >= parameters.n/4 &&
|
||||||
|
numOfOnes <= parameters.n/4 * 3 {
|
||||||
|
//fmt.Printf("hamming weight: %v\n", numOfOnes)
|
||||||
|
return true, numOfOnes
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, numOfOnes
|
||||||
|
}
|
||||||
|
|
||||||
|
//func isRegular(nSize, wCol, wRow int) bool {
|
||||||
|
// res := float64(nSize*wCol) / float64(wRow)
|
||||||
|
// m := math.Round(res)
|
||||||
|
//
|
||||||
|
// if int(m)*wRow == nSize*wCol {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return false
|
||||||
|
//}
|
||||||
|
|
||||||
|
//func SetDifficulty(nSize, wCol, wRow int) bool {
|
||||||
|
// if isRegular(nSize, wCol, wRow) {
|
||||||
|
// n = nSize
|
||||||
|
// wc = wCol
|
||||||
|
// wr = wRow
|
||||||
|
// m = int(n * wc / wr)
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// return false
|
||||||
|
//}
|
||||||
|
|
||||||
|
//func newIntMatrix(rows, cols int) intMatrix {
|
||||||
|
// m := intMatrix(make([][]int, rows))
|
||||||
|
// for i := range m {
|
||||||
|
// m[i] = make([]int, cols)
|
||||||
|
// }
|
||||||
|
// return m
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func newFloatMatrix(rows, cols int) floatMatrix {
|
||||||
|
// m := floatMatrix(make([][]float64, rows))
|
||||||
|
// for i := range m {
|
||||||
|
// m[i] = make([]float64, cols)
|
||||||
|
// }
|
||||||
|
// return m
|
||||||
|
//}
|
||||||
|
|
||||||
|
// New creates a full sized ethash PoW scheme and starts a background thread for
|
||||||
|
// remote mining, also optionally notifying a batch of remote services of new work
|
||||||
|
// packages.
|
||||||
|
|
||||||
|
func New(config Config, notify []string, noverify bool) *ECC {
|
||||||
|
if config.Log == nil {
|
||||||
|
config.Log = log.Root()
|
||||||
|
}
|
||||||
|
ecc := &ECC{
|
||||||
|
config: config,
|
||||||
|
update: make(chan struct{}),
|
||||||
|
hashrate: metrics.NewMeterForced(),
|
||||||
|
workCh: make(chan *sealTask),
|
||||||
|
fetchWorkCh: make(chan *sealWork),
|
||||||
|
submitWorkCh: make(chan *mineResult),
|
||||||
|
fetchRateCh: make(chan chan uint64),
|
||||||
|
submitRateCh: make(chan *hashrate),
|
||||||
|
}
|
||||||
|
if config.PowMode == ModeShared {
|
||||||
|
ecc.shared = sharedECC
|
||||||
|
}
|
||||||
|
ecc.remote = startRemoteSealer(ecc, notify, noverify)
|
||||||
|
return ecc
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTester(notify []string, noverify bool) *ECC {
|
||||||
|
ecc := &ECC{
|
||||||
|
config: Config{PowMode: ModeTest},
|
||||||
|
update: make(chan struct{}),
|
||||||
|
hashrate: metrics.NewMeterForced(),
|
||||||
|
workCh: make(chan *sealTask),
|
||||||
|
fetchWorkCh: make(chan *sealWork),
|
||||||
|
submitWorkCh: make(chan *mineResult),
|
||||||
|
fetchRateCh: make(chan chan uint64),
|
||||||
|
submitRateCh: make(chan *hashrate),
|
||||||
|
}
|
||||||
|
ecc.remote = startRemoteSealer(ecc, notify, noverify)
|
||||||
|
return ecc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts
|
||||||
|
// all blocks' seal as valid, though they still have to conform to the Ethereum
|
||||||
|
// consensus rules.
|
||||||
|
func NewFaker() *ECC {
|
||||||
|
return &ECC{
|
||||||
|
config: Config{
|
||||||
|
PowMode: ModeFake,
|
||||||
|
Log: log.Root(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFakeFailer creates a ethash consensus engine with a fake PoW scheme that
|
||||||
|
// accepts all blocks as valid apart from the single one specified, though they
|
||||||
|
// still have to conform to the Ethereum consensus rules.
|
||||||
|
func NewFakeFailer(fail uint64) *ECC {
|
||||||
|
return &ECC{
|
||||||
|
config: Config{
|
||||||
|
PowMode: ModeFake,
|
||||||
|
Log: log.Root(),
|
||||||
|
},
|
||||||
|
fakeFail: fail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFakeDelayer creates a ethash consensus engine with a fake PoW scheme that
|
||||||
|
// accepts all blocks as valid, but delays verifications by some time, though
|
||||||
|
// they still have to conform to the Ethereum consensus rules.
|
||||||
|
func NewFakeDelayer(delay time.Duration) *ECC {
|
||||||
|
return &ECC{
|
||||||
|
config: Config{
|
||||||
|
PowMode: ModeFake,
|
||||||
|
Log: log.Root(),
|
||||||
|
},
|
||||||
|
fakeDelay: delay,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFullFaker creates an ethash consensus engine with a full fake scheme that
|
||||||
|
// accepts all blocks as valid, without checking any consensus rules whatsoever.
|
||||||
|
func NewFullFaker() *ECC {
|
||||||
|
return &ECC{
|
||||||
|
config: Config{
|
||||||
|
PowMode: ModeFullFake,
|
||||||
|
Log: log.Root(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewShared creates a full sized ethash PoW shared between all requesters running
|
||||||
|
// in the same process.
|
||||||
|
//func NewShared() *ECC {
|
||||||
|
// return &ECC{shared: sharedECC}
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Close closes the exit channel to notify all backend threads exiting.
|
||||||
|
func (ecc *ECC) Close() error {
|
||||||
|
return ecc.StopRemoteSealer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopRemoteSealer stops the remote sealer
|
||||||
|
func (ecc *ECC) StopRemoteSealer() error {
|
||||||
|
ecc.closeOnce.Do(func() {
|
||||||
|
// Short circuit if the exit channel is not allocated.
|
||||||
|
if ecc.remote == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
close(ecc.remote.requestExit)
|
||||||
|
<-ecc.remote.exitCh
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Threads returns the number of mining threads currently enabled. This doesn't
|
||||||
|
// necessarily mean that mining is running!
|
||||||
|
func (ecc *ECC) Threads() int {
|
||||||
|
ecc.lock.Lock()
|
||||||
|
defer ecc.lock.Unlock()
|
||||||
|
|
||||||
|
return ecc.threads
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetThreads updates the number of mining threads currently enabled. Calling
|
||||||
|
// this method does not start mining, only sets the thread count. If zero is
|
||||||
|
// specified, the miner will use all cores of the machine. Setting a thread
|
||||||
|
// count below zero is allowed and will cause the miner to idle, without any
|
||||||
|
// work being done.
|
||||||
|
func (ecc *ECC) SetThreads(threads int) {
|
||||||
|
ecc.lock.Lock()
|
||||||
|
defer ecc.lock.Unlock()
|
||||||
|
|
||||||
|
// If we're running a shared PoW, set the thread count on that instead
|
||||||
|
if ecc.shared != nil {
|
||||||
|
ecc.shared.SetThreads(threads)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Update the threads and ping any running seal to pull in any changes
|
||||||
|
ecc.threads = threads
|
||||||
|
select {
|
||||||
|
case ecc.update <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hashrate implements PoW, returning the measured rate of the search invocations
|
||||||
|
// per second over the last minute.
|
||||||
|
// Note the returned hashrate includes local hashrate, but also includes the total
|
||||||
|
// hashrate of all remote miner.
|
||||||
|
func (ecc *ECC) Hashrate() float64 {
|
||||||
|
// Short circuit if we are run the ecc in normal/test mode.
|
||||||
|
|
||||||
|
var res = make(chan uint64, 1)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ecc.remote.fetchRateCh <- res:
|
||||||
|
case <-ecc.remote.exitCh:
|
||||||
|
// Return local hashrate only if ecc is stopped.
|
||||||
|
return ecc.hashrate.Rate1()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gather total submitted hash rate of remote sealers.
|
||||||
|
return ecc.hashrate.Rate1() + float64(<-res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIs implements consensus.Engine, returning the user facing RPC APIs.
|
||||||
|
func (ecc *ECC) APIs(chain consensus.ChainHeaderReader) []rpc.API {
|
||||||
|
// In order to ensure backward compatibility, we exposes ecc RPC APIs
|
||||||
|
// to both eth and ecc namespaces.
|
||||||
|
return []rpc.API{
|
||||||
|
{
|
||||||
|
Namespace: "eth",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: &API{ecc},
|
||||||
|
Public: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Namespace: "ecc",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: &API{ecc},
|
||||||
|
Public: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasher is a repetitive hasher allowing the same hash data structures to be
|
||||||
|
// reused between hash runs instead of requiring new ones to be created.
|
||||||
|
type hasher func(dest []byte, data []byte)
|
||||||
|
|
||||||
|
// makeHasher creates a repetitive hasher, allowing the same hash data structures to
|
||||||
|
// be reused between hash runs instead of requiring new ones to be created. The returned
|
||||||
|
// function is not thread safe!
|
||||||
|
func makeHasher(h hash.Hash) hasher {
|
||||||
|
// sha3.state supports Read to get the sum, use it to avoid the overhead of Sum.
|
||||||
|
// Read alters the state but we reset the hash before every operation.
|
||||||
|
type readerHash interface {
|
||||||
|
hash.Hash
|
||||||
|
Read([]byte) (int, error)
|
||||||
|
}
|
||||||
|
rh, ok := h.(readerHash)
|
||||||
|
if !ok {
|
||||||
|
panic("can't find Read method on hash")
|
||||||
|
}
|
||||||
|
outputLen := rh.Size()
|
||||||
|
return func(dest []byte, data []byte) {
|
||||||
|
rh.Reset()
|
||||||
|
rh.Write(data)
|
||||||
|
rh.Read(dest[:outputLen])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// seedHash is the seed to use for generating a verification cache and the mining
|
||||||
|
// dataset.
|
||||||
|
func seedHash(block uint64) []byte {
|
||||||
|
seed := make([]byte, 32)
|
||||||
|
if block < epochLength {
|
||||||
|
return seed
|
||||||
|
}
|
||||||
|
keccak256 := makeHasher(sha3.NewLegacyKeccak256())
|
||||||
|
for i := 0; i < int(block/epochLength); i++ {
|
||||||
|
keccak256(seed, seed)
|
||||||
|
}
|
||||||
|
return seed
|
||||||
|
}
|
||||||
|
|
||||||
|
//// SeedHash is the seed to use for generating a verification cache and the mining
|
||||||
|
//// dataset.
|
||||||
|
func SeedHash(block uint64) []byte {
|
||||||
|
return seedHash(block)
|
||||||
|
}
|
||||||
90
consensus/eccpow/algorithm_test.go
Normal file
90
consensus/eccpow/algorithm_test.go
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
package eccpow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cryptoecc/ETH-ECC/common"
|
||||||
|
"github.com/cryptoecc/ETH-ECC/common/hexutil"
|
||||||
|
"github.com/cryptoecc/ETH-ECC/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRandomSeed(t *testing.T) {
|
||||||
|
header := new(types.Header)
|
||||||
|
header.Difficulty = ProbToDifficulty(Table[0].miningProb)
|
||||||
|
parameters, _ := setParameters(header)
|
||||||
|
|
||||||
|
a := generateH(parameters)
|
||||||
|
b := generateH(parameters)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(a, b) {
|
||||||
|
t.Error("Wrong matrix")
|
||||||
|
} else {
|
||||||
|
t.Log("Pass")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLDPC(t *testing.T) {
|
||||||
|
/*
|
||||||
|
prevHash := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
curHash := hexutil.MustDecode("0xca2ff06caae7c94dc968be7d76d0fbf60dd2e1989ee9bf0d5931e48564d5143b")
|
||||||
|
nonce, mixDigest := RunLDPC(prevHash, curHash)
|
||||||
|
|
||||||
|
wantDigest := hexutil.MustDecode("0x535306ee4b42c92aecd0e71fca98572064f049c2babb2769faa3bbd87d67ec2d")
|
||||||
|
|
||||||
|
if !bytes.Equal(mixDigest, wantDigest) {
|
||||||
|
t.Errorf("light hashimoto digest mismatch: have %x, want %x", mixDigest, wantDigest)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(nonce)
|
||||||
|
*/
|
||||||
|
header := new(types.Header)
|
||||||
|
//t.Log(hexutil.Encode(header.ParentHash))
|
||||||
|
header.Difficulty = ProbToDifficulty(Table[0].miningProb)
|
||||||
|
var hash []byte
|
||||||
|
_, hashVector, outputWord, LDPCNonce, digest := RunOptimizedConcurrencyLDPC(header, hash)
|
||||||
|
|
||||||
|
t.Logf("Hash vector : %v\n", hashVector)
|
||||||
|
t.Logf("Outputword : %v\n", outputWord)
|
||||||
|
t.Logf("LDPC Nonce : %v\n", LDPCNonce)
|
||||||
|
t.Logf("Digest : %v\n", digest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkECCPoW(b *testing.B) {
|
||||||
|
//prevHash := hexutil.MustDecode("0xd783efa4d392943503f28438ad5830b2d5964696ffc285f338585e9fe0a37a05")
|
||||||
|
//curHash := hexutil.MustDecode("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
|
||||||
|
|
||||||
|
header := new(types.Header)
|
||||||
|
header.Difficulty = ProbToDifficulty(Table[0].miningProb)
|
||||||
|
var hash []byte
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
RunOptimizedConcurrencyLDPC(header, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestHashRate(t *testing.T) {
|
||||||
|
var (
|
||||||
|
hashrate = []hexutil.Uint64{100, 200, 300}
|
||||||
|
expect uint64
|
||||||
|
ids = []common.Hash{common.HexToHash("a"), common.HexToHash("b"), common.HexToHash("c")}
|
||||||
|
)
|
||||||
|
ecc := NewTester(nil, false)
|
||||||
|
defer ecc.Close()
|
||||||
|
|
||||||
|
if tot := ecc.Hashrate(); tot != 0 {
|
||||||
|
t.Error("expect the result should be zero")
|
||||||
|
}
|
||||||
|
|
||||||
|
api := &API{ecc}
|
||||||
|
for i := 0; i < len(hashrate); i++ {
|
||||||
|
if res := api.SubmitHashRate(hashrate[i], ids[i]); !res {
|
||||||
|
t.Error("remote miner submit hashrate failed")
|
||||||
|
}
|
||||||
|
expect += uint64(hashrate[i])
|
||||||
|
}
|
||||||
|
if tot := ecc.Hashrate(); tot != float64(expect) {
|
||||||
|
t.Error("expect total hashrate should be same")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue