我正在尝试编写一个同时挖掘比特币块的程序。我已经设置好了,这样每个程序都有一个初始的起始随机数,每个随机数都是4ie的一小部分。2**64 - 1 (max number of uint64 type)/1或2或3或4.
只有一个矿工会遇到正确的nonce,当这种情况发生时,我希望它通过通道传递给矿工管理器,当这种情况发生时,我希望其他3个矿工停止他们正在做的事情。
唯一的问题是我不知道如何销毁一个正在运行的程序,或者是否有一种方法来做我所要求的。
func miner(blockNumber int, transactions string, previousHash string, zeroPrefix string, startNonce uint64, nonceChan chan uint64, hashChan chan string) {
var text string
var newHash string
for {
text = strconv.Itoa(blockNumber) + transactions + previousHash + strconv.FormatUint(startNonce, 10)
newHash = encrypt(text)
if startswith(newHash, zeroPrefix) {
nonceChan <- startNonce
hashChan <- newHash
close(nonceChan)
close(hashChan)
break
} else {
startNonce++
}
}
}
func mine(blockNumber int, transactions string, previousHash string, zeroPrefix int) Block {
var prefixString string
var newHash string
var nonce uint64
var startNonce uint64
nonceChan := make(chan uint64)
hashChan := make(chan string)
for i := 0; i < zeroPrefix; i++ {
prefixString += "0"
}
start := time.Now()
for i := 0; i < 4; i++{
// This line is for deciding at what nonce value a miner should start at.
startNonce = uint64((float64(i) / 4) * math.Pow(2, 64))
go func() {
fmt.Println("Started miner with start nonce of", startNonce)
miner(blockNumber, transactions, previousHash, prefixString, startNonce, nonceChan, hashChan)
}()
}
nonce = <- nonceChan
newHash = <- hashChan
// Here is where I would like to destroy the other three miners
block := Block{
blockNumber,
transactions,
previousHash,
newHash,
nonce,
zeroPrefix,
time.Since(start),
}
return block
}
在函数中创建一个ctx, cancel := context.WithCancel(context.Background())
,用于启动所有的goout程,并将其传递给所有的goout程(作为函数中的第一个参数)
当需要取消工作时,调用cancel
函数。你可以这样做,例如在main
函数收到结果后。
在每个例程中检查ctx.Done
的选择(在for
循环中):
select {
case <-ctx.Done():
return
default:
}
// continue mining
例子:
func miner(ctx context.Context, ...) {
defer func() {
// any necessary cleanup
}
for {
select {
case <-ctx.Done():
// abort was called for: exit
return
default:
}
// continue mining
}
}
func mine() {
// use a single channel to get the result. You could
// block yourself if you use multiple channels
chResult := make(chan result)
// create context
ctx, cancel := context.WithCancel(context.Background())
for i := 0; i < 4; i++{
// ...
// pass the context into the miner
go miner(ctx, chResult, ...)
}
// block for first miner to be successful
res := <-chResult
// cancel the other routines
cancel()
// ...
}
result
可以是:
struct result {
hash string
nonce uint64
}
你可以使用context
来处理go例程的终止。
context :
包上下文定义了上下文类型,它在API边界和进程之间携带截止日期、取消信号和其他请求范围的值。
ctx, cancel := context.WithCancel(context.Background())
用这个可以创建一个context
和cancel
函数。
只要在你的go例程中传递ctx and cancel
,当你在任何go例程中完成时,只需调用cancel()
func()
。然后ctx.done()
将为真,然后switch的第一种情况将为真,它将从所有go例程返回。
func miner( ctx context.Context, blockNumber int, transactions string, previousHash string, zeroPrefix string, startNonce uint64, nonceChan chan uint64, hashChan chan string) {
var text string
var newHash string
for {
select {
case <-ctx.Done(): // if cancel() execute
return
default:
text = strconv.Itoa(blockNumber) + transactions + previousHash + strconv.FormatUint(startNonce, 10)
newHash = encrypt(text)
if startswith(newHash, zeroPrefix) {
nonceChan <- startNonce
hashChan <- newHash
close(nonceChan)
close(hashChan)
break
} else {
startNonce++
}
}
}
}
func mine(blockNumber int, transactions string, previousHash string, zeroPrefix int) Block {
var prefixString string
var newHash string
var nonce uint64
var startNonce uint64
nonceChan := make(chan uint64)
hashChan := make(chan string)
for i := 0; i < zeroPrefix; i++ {
prefixString += "0"
}
start := time.Now()
ctx, cancel := context.WithCancel(context.Background())
for i := 0; i < 4; i++{
// This line is for deciding at what nonce value a miner should start at.
startNonce = uint64((float64(i) / 4) * math.Pow(2, 64))
go func(ctx context.Context) {
fmt.Println("Started miner with start nonce of", startNonce)
miner(ctx, blockNumber, transactions, previousHash, prefixString, startNonce, nonceChan, hashChan)
}(ctx)
}
nonce = <- nonceChan
newHash = <- hashChan
cancel()
// Here is where I would like to destroy the other three miners
block := Block{
blockNumber,
transactions,
previousHash,
newHash,
nonce,
zeroPrefix,
time.Since(start),
}
return block
}