Skip to content

Commit

Permalink
cmd: add multi-threading
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger committed Sep 2, 2024
1 parent 719f413 commit 4e9c427
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 60 deletions.
78 changes: 42 additions & 36 deletions cmd/cpuminerd/main.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
package main

import (
"context"
"errors"
"flag"
"fmt"
"math/big"
"os"
"os/signal"
"runtime"
"sync"
"time"

"go.sia.tech/core/types"
"go.sia.tech/coreutils"
"go.sia.tech/walletd/api"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"lukechampine.com/frand"
)

func runCPUMiner(c *api.Client, minerAddr types.Address, log *zap.Logger) {
log.Info("starting cpu miner", zap.String("minerAddr", minerAddr.String()))
start := time.Now()
func runCPUMiner(ctx context.Context, c *api.Client, minerAddr types.Address, log *zap.Logger) {
log.Info("starting miner", zap.String("minerAddr", minerAddr.String()))

check := func(msg string, err error) bool {
if err != nil {
Expand All @@ -28,50 +29,38 @@ func runCPUMiner(c *api.Client, minerAddr types.Address, log *zap.Logger) {
return true
}

start := time.Now()
for {
elapsed := time.Since(start)
select {
case <-ctx.Done():
return
default:
}

cs, err := c.ConsensusTipState()
if !check("failed to get consensus tip state", err) {
continue
}

d, _ := new(big.Int).SetString(cs.Difficulty.String(), 10)
d.Mul(d, big.NewInt(int64(1+elapsed)))
log := log.With(zap.Uint64("height", cs.Index.Height+1), zap.Stringer("parentID", cs.Index.ID), zap.Stringer("difficulty", d))
log := log.With(zap.Uint64("height", cs.Index.Height+1), zap.Stringer("parentID", cs.Index.ID))

log.Debug("mining block")
txns, v2txns, err := c.TxpoolTransactions()
if !check("failed to get txpool transactions", err) {
continue
}

b := types.Block{
ParentID: cs.Index.ID,
Nonce: cs.NonceFactor() * frand.Uint64n(100),
Timestamp: types.CurrentTimestamp(),
MinerPayouts: []types.SiacoinOutput{{Address: minerAddr, Value: cs.BlockReward()}},
Transactions: txns,
}
for _, txn := range txns {
b.MinerPayouts[0].Value = b.MinerPayouts[0].Value.Add(txn.TotalFees())
}
for _, txn := range v2txns {
b.MinerPayouts[0].Value = b.MinerPayouts[0].Value.Add(txn.MinerFee)
}
if len(v2txns) > 0 || cs.Index.Height+1 >= cs.Network.HardforkV2.RequireHeight {
b.V2 = &types.V2BlockData{
Height: cs.Index.Height + 1,
Transactions: v2txns,
}
b.V2.Commitment = cs.Commitment(cs.TransactionsCommitment(b.Transactions, b.V2Transactions()), b.MinerPayouts[0].Address)
b, err := mineBlock(ctx, cs, txns, v2txns, minerAddr)
if errors.Is(err, context.Canceled) {
return // shutting down
} else if errors.Is(err, context.DeadlineExceeded) {
continue // timeout, try again
} else if err != nil {
log.Error("failed to mine block", zap.Error(err)) // should never happen
return
}

if !coreutils.FindBlockNonce(cs, &b, time.Minute) {
log.Debug("failed to find nonce")
continue
}
log.Debug("found nonce", zap.Uint64("nonce", b.Nonce))
index := types.ChainIndex{Height: cs.Index.Height + 1, ID: b.ID()}
tip, err := c.ConsensusTip()
if !check("failed to get consensus tip:", err) {
continue
Expand All @@ -82,7 +71,8 @@ func runCPUMiner(c *api.Client, minerAddr types.Address, log *zap.Logger) {
} else if err := c.SyncerBroadcastBlock(b); err != nil {
log.Error("mined invalid block", zap.Error(err))
}
log.Info("mined block", zap.Stringer("blockID", index.ID), zap.Stringer("fees", b.MinerPayouts[0].Value), zap.Int("transactions", len(b.Transactions)), zap.Int("v2transactions", len(b.V2Transactions())))
log.Info("mined block", zap.Duration("elapsed", time.Since(start)), zap.Stringer("blockID", b.ID()), zap.Stringer("reward", b.MinerPayouts[0].Value), zap.Int("transactions", len(b.Transactions)), zap.Int("v2transactions", len(b.V2Transactions())))
start = time.Now() // reset the timer
}
}

Expand All @@ -105,6 +95,8 @@ func parseLogLevel(level string) zap.AtomicLevel {

func main() {
var (
threads int

minerAddrStr string

apiAddress string
Expand All @@ -117,8 +109,12 @@ func main() {
flag.StringVar(&apiAddress, "api", "localhost:9980", "address of the walletd API")
flag.StringVar(&apiPassword, "password", "", "password for the walletd API")
flag.StringVar(&logLevel, "log.level", "info", "log level")
flag.IntVar(&threads, "threads", runtime.NumCPU(), "number of threads to use for mining")
flag.Parse()

ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()

var address types.Address
if err := address.UnmarshalText([]byte(minerAddrStr)); err != nil {
panic(err)
Expand All @@ -143,5 +139,15 @@ func main() {

zap.RedirectStdLog(log)

runCPUMiner(c, address, log)
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
runCPUMiner(ctx, c, address, log)
}()
}

<-ctx.Done()
wg.Wait()
}
77 changes: 77 additions & 0 deletions cmd/cpuminerd/mine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"context"
"encoding/binary"
"time"

"go.sia.tech/core/consensus"
"go.sia.tech/core/types"
)

// mineBlock constructs a block from the provided address and the transactions
// in the txpool, and attempts to find a nonce for it that meets the PoW target.
func mineBlock(ctx context.Context, cs consensus.State, txns []types.Transaction, v2Txns []types.V2Transaction, addr types.Address) (types.Block, error) {
b := types.Block{
ParentID: cs.Index.ID,
Timestamp: types.CurrentTimestamp(),
MinerPayouts: []types.SiacoinOutput{{
Value: cs.BlockReward(),
Address: addr,
}},
}

if cs.Index.Height >= cs.Network.HardforkV2.AllowHeight {
b.V2 = &types.V2BlockData{
Height: cs.Index.Height + 1,
}
}

var weight uint64
for _, txn := range txns {
if weight += cs.TransactionWeight(txn); weight > cs.MaxBlockWeight() {
break
}
b.Transactions = append(b.Transactions, txn)
b.MinerPayouts[0].Value = b.MinerPayouts[0].Value.Add(txn.TotalFees())
}
for _, txn := range v2Txns {
if weight += cs.V2TransactionWeight(txn); weight > cs.MaxBlockWeight() {
break
}
b.V2.Transactions = append(b.V2.Transactions, txn)
b.MinerPayouts[0].Value = b.MinerPayouts[0].Value.Add(txn.MinerFee)
}
if b.V2 != nil {
b.V2.Commitment = cs.Commitment(cs.TransactionsCommitment(b.Transactions, b.V2Transactions()), addr)
}

b.Nonce = 0
buf := make([]byte, 32+8+8+32)
binary.LittleEndian.PutUint64(buf[32:], b.Nonce)
binary.LittleEndian.PutUint64(buf[40:], uint64(b.Timestamp.Unix()))
if b.V2 != nil {
copy(buf[:32], "sia/id/block|")
copy(buf[48:], b.V2.Commitment[:])
} else {
root := b.MerkleRoot()
copy(buf[:32], b.ParentID[:])
copy(buf[48:], root[:])
}
factor := cs.NonceFactor()

ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
defer cancel()

for types.BlockID(types.HashBytes(buf)).CmpWork(cs.ChildTarget) < 0 {
select {
case <-ctx.Done():
return types.Block{}, ctx.Err()
default:
}

b.Nonce += factor
binary.LittleEndian.PutUint64(buf[32:], b.Nonce)
}
return b, nil
}
19 changes: 9 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
module go.sia.tech/cpuminerd

go 1.21.8
go 1.22.5

toolchain go1.21.11
toolchain go1.23.0

require (
go.sia.tech/core v0.2.7
go.sia.tech/coreutils v0.0.5
go.sia.tech/walletd v0.1.1-alpha.0.20240610172105-eb95d4161b91
go.sia.tech/core v0.4.5
go.sia.tech/walletd v0.8.1-0.20240901222528-4a6f567605f6
go.uber.org/zap v1.27.0
lukechampine.com/frand v1.4.2
)

require (
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
go.etcd.io/bbolt v1.3.10 // indirect
go.sia.tech/jape v0.11.2-0.20240306154058-9832414a5385 // indirect
go.sia.tech/coreutils v0.3.1 // indirect
go.sia.tech/jape v0.12.1 // indirect
go.sia.tech/mux v1.2.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/tools v0.22.0 // indirect
lukechampine.com/frand v1.4.2 // indirect
)
28 changes: 14 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,33 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
go.sia.tech/core v0.2.7 h1:9Q/3BHL6ziAMPeiko863hhTD/Zs2s7OqEUiPKouDny8=
go.sia.tech/core v0.2.7/go.mod h1:BMgT/reXtgv6XbDgUYTCPY7wSMbspDRDs7KMi1vL6Iw=
go.sia.tech/coreutils v0.0.5 h1:Jj03VrqAayYHgA9fwV13+X88WB+Wr1p8wuLw2B8d2FI=
go.sia.tech/coreutils v0.0.5/go.mod h1:SkSpHeq3tBh2ff4HXuBk2WtlhkYQQtdcvU4Yv1Rd2bU=
go.sia.tech/jape v0.11.2-0.20240306154058-9832414a5385 h1:Gho1g6pkv56o6Ut9cez/Yu5o4xlA8WNkDbPn6RWXL7g=
go.sia.tech/jape v0.11.2-0.20240306154058-9832414a5385/go.mod h1:wU+h6Wh5olDjkPXjF0tbZ1GDgoZ6VTi4naFw91yyWC4=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.sia.tech/core v0.4.5 h1:w2D3Mx29UmK1aFd9R7uHFo5JUSTqu3+92NHoRFv3CaU=
go.sia.tech/core v0.4.5/go.mod h1:Zuq0Tn2aIXJyO0bjGu8cMeVWe+vwQnUfZhG1LCmjD5c=
go.sia.tech/coreutils v0.3.1 h1:FLIBM4ryLFvwkZVv8Yyn3KZsUdqX6pX8moS3xfQX5M0=
go.sia.tech/coreutils v0.3.1/go.mod h1:qOBvtTS14Q2lSbY+S3u39AntpttL5kuIv7P8NktKYw0=
go.sia.tech/jape v0.12.1 h1:xr+o9V8FO8ScRqbSaqYf9bjj1UJ2eipZuNcI1nYousU=
go.sia.tech/jape v0.12.1/go.mod h1:wU+h6Wh5olDjkPXjF0tbZ1GDgoZ6VTi4naFw91yyWC4=
go.sia.tech/mux v1.2.0 h1:ofa1Us9mdymBbGMY2XH/lSpY8itFsKIo/Aq8zwe+GHU=
go.sia.tech/mux v1.2.0/go.mod h1:Yyo6wZelOYTyvrHmJZ6aQfRoer3o4xyKQ4NmQLJrBSo=
go.sia.tech/walletd v0.1.1-alpha.0.20240610172105-eb95d4161b91 h1:9saK9WcYSK3DDwj6aWyM3MUYlyZaJFiYzdm7KHg4I+Y=
go.sia.tech/walletd v0.1.1-alpha.0.20240610172105-eb95d4161b91/go.mod h1:1CaApRlon10cIDnocnErbolh416CiUeP5jgEbVtmWx8=
go.sia.tech/walletd v0.8.1-0.20240901222528-4a6f567605f6 h1:bYu3hFLxUuh0JrLq2HEEgsMMLn1yxbZzaJ7GlSQJPog=
go.sia.tech/walletd v0.8.1-0.20240901222528-4a6f567605f6/go.mod h1:6blaOwGiC4FetxDClwwBawAtQzdi0bdvw+bw5GF/f94=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down

0 comments on commit 4e9c427

Please sign in to comment.