Compare commits

...

11 Commits

Author SHA1 Message Date
Kaspa Profiler
7bed86dc1b Update changelog.txt 2021-11-11 09:30:12 +02:00
Ori Newman
9b81f5145e Increase p2p msg size and reset utxo after ibd (#1847)
* Don't build unnecessary binaries

* Reset UTXO index after IBD

* Enlarge max msg size to 1gb

* Fix UTXO chunks logic

* Revert UTXO set override change

* Fix sendPruningPointUTXOSet

* Increase tests timeout to 20 minutes

Co-authored-by: Kaspa Profiler <>
2021-11-11 09:27:07 +02:00
Kaspa Profiler
cd8341ef57 Update to version 0.11.2 2021-11-10 23:19:25 +02:00
Ori Newman
ad8bdbed21 Update changelog (#1845)
Co-authored-by: Kaspa Profiler <>
2021-11-09 00:32:56 +02:00
Elichai Turkel
7cdceb6df0 Cache the miner state (#1844)
* Implement a MinerState to cache the matrix and friends

* Modify the miner and related code to use the new MinerCache

* Change MinerState to State

* Make go lint happy

Co-authored-by: Ori Newman <orinewman1@gmail.com>
Co-authored-by: Kaspa Profiler <>
2021-11-09 00:12:30 +02:00
stasatdaglabs
cc5248106e Update to version 0.11.1 2021-11-08 09:01:52 +02:00
Elichai Turkel
e3463b7268 Replace Keccak256 in oPoW with CSHAKE256 with domain seperation (#1842)
* Replace keccak with CSHAKE256 in oPoW

* Add benchmarks to hash writers to compare blake2b to the CSHAKE

* Update genesis blocks

* Update tests

* Define genesis's block level to be the maximal one

* Add message to genesis coinbase

* Add comments to genesis coinbase

* Fix tests

Co-authored-by: Ori Newman <orinewman1@gmail.com>
2021-11-07 18:36:30 +02:00
Ori Newman
a2173ef80a Switch PoW to a keccak heavyhash variant (#1841)
* Add another hash domain for HeavyHash

* Add a xoShiRo256PlusPlus implementation

* Add a HeavyHash implementation

* Replace our current PoW algorithm with oPoW

* Change to pow hash to keccak256

* Fix genesis

* Fix tests

Co-authored-by: Elichai Turkel <elichai.turkel@gmail.com>
2021-11-07 11:17:15 +02:00
stasatdaglabs
aeb4500b61 Add the daglabs-dev mainnet dnsseeder. (#1840) 2021-11-07 10:39:54 +02:00
Ori Newman
0a1daae319 Allow mainnet flag and raise wallet fee (#1838)
Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com>
2021-11-07 10:04:27 +02:00
stasatdaglabs
131cd3357e Rename FixedSubsidySwitchHashRateDifference to FixedSubsidySwitchHashRateThreshold and set its value to 150GH/s. (#1837) 2021-11-07 09:33:39 +02:00
37 changed files with 708 additions and 343 deletions

View File

@@ -1,7 +1,7 @@
name: Build and upload assets
on:
release:
types: [published]
types: [ published ]
jobs:
build:
@@ -36,7 +36,7 @@ jobs:
# `-tags netgo,osusergo` means use pure go replacements for "os/user" and "net"
# `-s -w` strips the binary to produce smaller size binaries
run: |
go build -v -ldflags="-s -w -extldflags=-static" -tags netgo,osusergo -o ./bin/ ./...
go build -v -ldflags="-s -w -extldflags=-static" -tags netgo,osusergo -o ./bin/ . ./cmd/...
archive="bin/kaspad-${{ github.event.release.tag_name }}-linux.zip"
asset_name="kaspad-${{ github.event.release.tag_name }}-linux.zip"
zip -r "${archive}" ./bin/*
@@ -47,7 +47,7 @@ jobs:
if: runner.os == 'Windows'
shell: bash
run: |
go build -v -ldflags="-s -w" -o bin/ ./...
go build -v -ldflags="-s -w" -o bin/ . ./cmd/...
archive="bin/kaspad-${{ github.event.release.tag_name }}-win64.zip"
asset_name="kaspad-${{ github.event.release.tag_name }}-win64.zip"
powershell "Compress-Archive bin/* \"${archive}\""
@@ -57,7 +57,7 @@ jobs:
- name: Build on MacOS
if: runner.os == 'macOS'
run: |
go build -v -ldflags="-s -w" -o ./bin/ ./...
go build -v -ldflags="-s -w" -o ./bin/ . ./cmd/...
archive="bin/kaspad-${{ github.event.release.tag_name }}-osx.zip"
asset_name="kaspad-${{ github.event.release.tag_name }}-osx.zip"
zip -r "${archive}" ./bin/*

View File

@@ -102,14 +102,17 @@ func (flow *handleRequestPruningPointUTXOSetFlow) sendPruningPointUTXOSet(
return err
}
if len(pruningPointUTXOs) < step && chunksSent%ibdBatchSize == 0 {
finished := len(pruningPointUTXOs) < step
if finished && chunksSent%ibdBatchSize != 0 {
log.Debugf("Finished sending UTXOs for pruning block %s",
msgRequestPruningPointUTXOSet.PruningPointHash)
return flow.outgoingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks())
}
fromOutpoint = pruningPointUTXOs[len(pruningPointUTXOs)-1].Outpoint
if len(pruningPointUTXOs) > 0 {
fromOutpoint = pruningPointUTXOs[len(pruningPointUTXOs)-1].Outpoint
}
chunksSent++
// Wait for the peer to request more chunks every `ibdBatchSize` chunks
@@ -123,6 +126,13 @@ func (flow *handleRequestPruningPointUTXOSetFlow) sendPruningPointUTXOSet(
return protocolerrors.Errorf(true, "received unexpected message type. "+
"expected: %s, got: %s", appmessage.CmdRequestNextPruningPointUTXOSetChunk, message.Command())
}
if finished {
log.Debugf("Finished sending UTXOs for pruning block %s",
msgRequestPruningPointUTXOSet.PruningPointHash)
return flow.outgoingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks())
}
}
}
}

View File

@@ -21,7 +21,7 @@ go build $FLAGS -o kaspad .
if [ -n "${NO_PARALLEL}" ]
then
go test -parallel=1 $FLAGS ./...
go test -timeout 20m -parallel=1 $FLAGS ./...
else
go test $FLAGS ./...
go test -timeout 20m $FLAGS ./...
fi

View File

@@ -1,3 +1,15 @@
Kaspad v0.11.2 - 2021-11-11
===========================
Bug fixes:
* Enlarge p2p max message size to 1gb
* Fix UTXO chunks logic
* Increase tests timeout to 20 minutes
Kaspad v0.11.1 - 2021-11-09
===========================
Non-breaking changes:
* Cache the miner state
Kaspad v0.10.2 - 2021-05-18
===========================
Non-breaking changes:

View File

@@ -13,7 +13,6 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/difficulty"
"github.com/pkg/errors"
)
@@ -143,20 +142,20 @@ func mineNextBlock(mineWhenNotSynced bool) *externalapi.DomainBlock {
// In the rare case where the nonce space is exhausted for a specific
// block, it'll keep looping the nonce until a new block template
// is discovered.
block := getBlockForMining(mineWhenNotSynced)
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
headerForMining := block.Header.ToMutable()
headerForMining.SetNonce(nonce)
block, state := getBlockForMining(mineWhenNotSynced)
state.Nonce = nonce
atomic.AddUint64(&hashesTried, 1)
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
block.Header = headerForMining.ToImmutable()
if state.CheckProofOfWork() {
mutHeader := block.Header.ToMutable()
mutHeader.SetNonce(nonce)
block.Header = mutHeader.ToImmutable()
log.Infof("Found block %s with parents %s", consensushashing.BlockHash(block), block.Header.DirectParents())
return block
}
}
}
func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
func getBlockForMining(mineWhenNotSynced bool) (*externalapi.DomainBlock, *pow.State) {
tryCount := 0
const sleepTime = 500 * time.Millisecond
@@ -166,7 +165,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
tryCount++
shouldLog := (tryCount-1)%10 == 0
template, isSynced := templatemanager.Get()
template, state, isSynced := templatemanager.Get()
if template == nil {
if shouldLog {
log.Info("Waiting for the initial template")
@@ -182,7 +181,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
continue
}
return template
return template, state
}
}

View File

@@ -3,23 +3,26 @@ package templatemanager
import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
"sync"
)
var currentTemplate *externalapi.DomainBlock
var currentState *pow.State
var isSynced bool
var lock = &sync.Mutex{}
// Get returns the template to work on
func Get() (*externalapi.DomainBlock, bool) {
func Get() (*externalapi.DomainBlock, *pow.State, bool) {
lock.Lock()
defer lock.Unlock()
// Shallow copy the block so when the user replaces the header it won't affect the template here.
if currentTemplate == nil {
return nil, false
return nil, nil, false
}
block := *currentTemplate
return &block, isSynced
state := *currentState
return &block, &state, isSynced
}
// Set sets the current template to work on
@@ -31,6 +34,7 @@ func Set(template *appmessage.GetBlockTemplateResponseMessage) error {
lock.Lock()
defer lock.Unlock()
currentTemplate = block
currentState = pow.NewState(block.Header.ToMutable())
isSynced = template.IsSynced
return nil
}

View File

@@ -19,7 +19,7 @@ func Connect(address string) (pb.KaspawalletdClient, func(), error) {
conn, err := grpc.DialContext(ctx, address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return nil, nil, errors.New("kaspactl daemon is not running, start it with `kaspactl start-daemon`")
return nil, nil, errors.New("kaspawallet daemon is not running, start it with `kaspawallet start-daemon`")
}
return nil, nil, err
}

View File

@@ -28,7 +28,7 @@ func (s *server) CreateUnsignedTransaction(_ context.Context, request *pb.Create
}
// TODO: Implement a better fee estimation mechanism
const feePerInput = 1000
const feePerInput = 10000
selectedUTXOs, changeSompi, err := s.selectUTXOs(request.Amount, feePerInput)
if err != nil {
return nil, err

View File

@@ -206,7 +206,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
config.CoinbasePayloadScriptPublicKeyMaxLength,
config.GenesisHash,
config.FixedSubsidySwitchPruningPointInterval,
config.FixedSubsidySwitchHashRateDifference,
config.FixedSubsidySwitchHashRateThreshold,
dagTraversalManager,
ghostdagDataStore,
acceptanceDataStore,

View File

@@ -8,7 +8,6 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/virtual"
"github.com/kaspanet/kaspad/infrastructure/db/database"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util/difficulty"
"github.com/pkg/errors"
)
@@ -149,7 +148,8 @@ func (v *blockValidator) validateDifficulty(stagingArea *model.StagingArea,
// difficulty is not performed.
func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error {
// The target difficulty must be larger than zero.
target := difficulty.CompactToBig(header.Bits())
state := pow.NewState(header.ToMutable())
target := &state.Target
if target.Sign() <= 0 {
return errors.Wrapf(ruleerrors.ErrNegativeTarget, "block target difficulty of %064x is too low",
target)
@@ -163,7 +163,7 @@ func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error
// The block pow must be valid unless the flag to avoid proof of work checks is set.
if !v.skipPoW {
valid := pow.CheckProofOfWorkWithTarget(header.ToMutable(), target)
valid := state.CheckProofOfWork()
if !valid {
return errors.Wrap(ruleerrors.ErrInvalidPoW, "block has invalid proof of work")
}

View File

@@ -111,13 +111,13 @@ func TestPOW(t *testing.T) {
// solveBlockWithWrongPOW increments the given block's nonce until it gets wrong POW (for test!).
func solveBlockWithWrongPOW(block *externalapi.DomainBlock) *externalapi.DomainBlock {
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
headerForMining := block.Header.ToMutable()
initialNonce := uint64(0)
for i := initialNonce; i < math.MaxUint64; i++ {
headerForMining.SetNonce(i)
if !pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
block.Header = headerForMining.ToImmutable()
header := block.Header.ToMutable()
state := pow.NewState(header)
for i := uint64(0); i < math.MaxUint64; i++ {
state.Nonce = i
if !state.CheckProofOfWork() {
header.SetNonce(state.Nonce)
block.Header = header.ToImmutable()
return block
}
}

View File

@@ -49,7 +49,7 @@ func (c *coinbaseManager) isBlockRewardFixed(stagingArea *model.StagingArea, blo
blueWorkDifference := new(big.Int).Sub(highPruningPointHeader.BlueWork(), lowPruningPointHeader.BlueWork())
blueScoreDifference := new(big.Int).SetUint64(highPruningPointHeader.BlueScore() - lowPruningPointHeader.BlueScore())
estimatedAverageHashRate := new(big.Int).Div(blueWorkDifference, blueScoreDifference)
if estimatedAverageHashRate.Cmp(c.fixedSubsidySwitchHashRateDifference) >= 0 {
if estimatedAverageHashRate.Cmp(c.fixedSubsidySwitchHashRateThreshold) >= 0 {
return true, nil
}

View File

@@ -32,7 +32,7 @@ func TestBlockRewardSwitch(t *testing.T) {
// Set the hash rate difference such that the switch would trigger exactly
// on the `FixedSubsidySwitchPruningPointInterval + 1`th pruning point
workToAcceptGenesis := difficulty.CalcWork(consensusConfig.GenesisBlock.Header.Bits())
consensusConfig.FixedSubsidySwitchHashRateDifference = workToAcceptGenesis
consensusConfig.FixedSubsidySwitchHashRateThreshold = workToAcceptGenesis
// Set the min, max, and post-switch subsidies to values that would make it
// easy to tell whether the switch happened

View File

@@ -22,7 +22,7 @@ type coinbaseManager struct {
coinbasePayloadScriptPublicKeyMaxLength uint8
genesisHash *externalapi.DomainHash
fixedSubsidySwitchPruningPointInterval uint64
fixedSubsidySwitchHashRateDifference *big.Int
fixedSubsidySwitchHashRateThreshold *big.Int
databaseContext model.DBReader
dagTraversalManager model.DAGTraversalManager
@@ -364,7 +364,7 @@ func New(
coinbasePayloadScriptPublicKeyMaxLength uint8,
genesisHash *externalapi.DomainHash,
fixedSubsidySwitchPruningPointInterval uint64,
fixedSubsidySwitchHashRateDifference *big.Int,
fixedSubsidySwitchHashRateThreshold *big.Int,
dagTraversalManager model.DAGTraversalManager,
ghostdagDataStore model.GHOSTDAGDataStore,
@@ -385,7 +385,7 @@ func New(
coinbasePayloadScriptPublicKeyMaxLength: coinbasePayloadScriptPublicKeyMaxLength,
genesisHash: genesisHash,
fixedSubsidySwitchPruningPointInterval: fixedSubsidySwitchPruningPointInterval,
fixedSubsidySwitchHashRateDifference: fixedSubsidySwitchHashRateDifference,
fixedSubsidySwitchHashRateThreshold: fixedSubsidySwitchHashRateThreshold,
dagTraversalManager: dagTraversalManager,
ghostdagDataStore: ghostdagDataStore,

View File

@@ -22,6 +22,150 @@ func TestBlockWindow(t *testing.T) {
expectedWindow []string
}{
dagconfig.MainnetParams.Name: {
{
parents: []string{"A"},
id: "B",
expectedWindow: []string{},
},
{
parents: []string{"B"},
id: "C",
expectedWindow: []string{"B"},
},
{
parents: []string{"B"},
id: "D",
expectedWindow: []string{"B"},
},
{
parents: []string{"C", "D"},
id: "E",
expectedWindow: []string{"C", "D", "B"},
},
{
parents: []string{"C", "D"},
id: "F",
expectedWindow: []string{"C", "D", "B"},
},
{
parents: []string{"A"},
id: "G",
expectedWindow: []string{},
},
{
parents: []string{"G"},
id: "H",
expectedWindow: []string{"G"},
},
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "H", "C", "D", "B", "G"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "H", "C", "D", "B", "G"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "H", "C", "D", "B", "G"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "H", "C", "D", "B", "G"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "H", "C", "D", "B", "G"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "B"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"},
},
},
dagconfig.TestnetParams.Name: {
{
parents: []string{"A"},
id: "B",
expectedWindow: []string{},
},
{
parents: []string{"B"},
id: "C",
expectedWindow: []string{"B"},
},
{
parents: []string{"B"},
id: "D",
expectedWindow: []string{"B"},
},
{
parents: []string{"C", "D"},
id: "E",
expectedWindow: []string{"C", "D", "B"},
},
{
parents: []string{"C", "D"},
id: "F",
expectedWindow: []string{"C", "D", "B"},
},
{
parents: []string{"A"},
id: "G",
expectedWindow: []string{},
},
{
parents: []string{"G"},
id: "H",
expectedWindow: []string{"G"},
},
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "H", "C", "D", "G", "B"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "H", "C", "D", "G", "B"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "H", "C", "D", "G", "B"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "H", "C", "D", "G", "B"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "H", "C", "D", "G", "B"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "G"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"},
},
},
dagconfig.DevnetParams.Name: {
{
parents: []string{"A"},
id: "B",
@@ -93,7 +237,7 @@ func TestBlockWindow(t *testing.T) {
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"},
},
},
dagconfig.TestnetParams.Name: {
dagconfig.SimnetParams.Name: {
{
parents: []string{"A"},
id: "B",
@@ -110,12 +254,12 @@ func TestBlockWindow(t *testing.T) {
expectedWindow: []string{"B"},
},
{
parents: []string{"C", "D"},
parents: []string{"D", "C"},
id: "E",
expectedWindow: []string{"D", "C", "B"},
},
{
parents: []string{"C", "D"},
parents: []string{"D", "C"},
id: "F",
expectedWindow: []string{"D", "C", "B"},
},
@@ -165,150 +309,6 @@ func TestBlockWindow(t *testing.T) {
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"},
},
},
dagconfig.DevnetParams.Name: {
{
parents: []string{"A"},
id: "B",
expectedWindow: []string{},
},
{
parents: []string{"B"},
id: "C",
expectedWindow: []string{"B"},
},
{
parents: []string{"B"},
id: "D",
expectedWindow: []string{"B"},
},
{
parents: []string{"D", "C"},
id: "E",
expectedWindow: []string{"D", "C", "B"},
},
{
parents: []string{"D", "C"},
id: "F",
expectedWindow: []string{"D", "C", "B"},
},
{
parents: []string{"A"},
id: "G",
expectedWindow: []string{},
},
{
parents: []string{"G"},
id: "H",
expectedWindow: []string{"G"},
},
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "D", "C", "H", "G", "B"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "D", "C", "H", "G", "B"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "D", "C", "H", "G", "B"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "D", "C", "H", "G", "B"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "C", "H", "G", "B"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "G"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"},
},
},
dagconfig.SimnetParams.Name: {
{
parents: []string{"A"},
id: "B",
expectedWindow: []string{},
},
{
parents: []string{"B"},
id: "C",
expectedWindow: []string{"B"},
},
{
parents: []string{"B"},
id: "D",
expectedWindow: []string{"B"},
},
{
parents: []string{"D", "C"},
id: "E",
expectedWindow: []string{"C", "D", "B"},
},
{
parents: []string{"D", "C"},
id: "F",
expectedWindow: []string{"C", "D", "B"},
},
{
parents: []string{"A"},
id: "G",
expectedWindow: []string{},
},
{
parents: []string{"G"},
id: "H",
expectedWindow: []string{"G"},
},
{
parents: []string{"H", "F"},
id: "I",
expectedWindow: []string{"F", "C", "D", "H", "G", "B"},
},
{
parents: []string{"I"},
id: "J",
expectedWindow: []string{"I", "F", "C", "D", "H", "G", "B"},
},
{
parents: []string{"J"},
id: "K",
expectedWindow: []string{"J", "I", "F", "C", "D", "H", "G", "B"},
},
{
parents: []string{"K"},
id: "L",
expectedWindow: []string{"K", "J", "I", "F", "C", "D", "H", "G", "B"},
},
{
parents: []string{"L"},
id: "M",
expectedWindow: []string{"L", "K", "J", "I", "F", "C", "D", "H", "G", "B"},
},
{
parents: []string{"M"},
id: "N",
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "G"},
},
{
parents: []string{"N"},
id: "O",
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"},
},
},
}
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
consensusConfig.K = 1

View File

@@ -19,6 +19,12 @@ import (
func TestDifficulty(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
// Mainnet's genesis is too new, so if we'll build on it we'll get to the future very quickly.
// TODO: Once it gets older, we should unskip this test.
if consensusConfig.Name == "kaspa-mainnet" {
return
}
if consensusConfig.DisableDifficultyAdjustment {
return
}
@@ -132,7 +138,7 @@ func TestDifficulty(t *testing.T) {
case dagconfig.TestnetParams.Name, dagconfig.DevnetParams.Name:
expectedBits = uint32(0x1e7f83df)
case dagconfig.MainnetParams.Name:
expectedBits = uint32(0x207f83df)
expectedBits = uint32(0x1e7f83df)
}
if tip.Header.Bits() != expectedBits {

View File

@@ -37,10 +37,10 @@ func TestPruning(t *testing.T) {
dagconfig.SimnetParams.Name: "1582",
},
"dag-for-test-pruning.json": {
dagconfig.MainnetParams.Name: "503",
dagconfig.MainnetParams.Name: "502",
dagconfig.TestnetParams.Name: "502",
dagconfig.DevnetParams.Name: "503",
dagconfig.SimnetParams.Name: "503",
dagconfig.DevnetParams.Name: "502",
dagconfig.SimnetParams.Name: "502",
},
}

View File

@@ -4,6 +4,7 @@ import (
"crypto/sha256"
"github.com/pkg/errors"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/sha3"
)
const (
@@ -13,6 +14,7 @@ const (
transcationSigningECDSADomain = "TransactionSigningHashECDSA"
blockDomain = "BlockHash"
proofOfWorkDomain = "ProofOfWorkHash"
heavyHashDomain = "HeavyHash"
merkleBranchDomain = "MerkleBranchHash"
)
@@ -65,12 +67,15 @@ func NewBlockHashWriter() HashWriter {
}
// NewPoWHashWriter Returns a new HashWriter used for the PoW function
func NewPoWHashWriter() HashWriter {
blake, err := blake2b.New256([]byte(proofOfWorkDomain))
if err != nil {
panic(errors.Wrapf(err, "this should never happen. %s is less than 64 bytes", proofOfWorkDomain))
}
return HashWriter{blake}
func NewPoWHashWriter() ShakeHashWriter {
shake256 := sha3.NewCShake256(nil, []byte(proofOfWorkDomain))
return ShakeHashWriter{shake256}
}
// NewHeavyHashWriter Returns a new HashWriter used for the HeavyHash function
func NewHeavyHashWriter() ShakeHashWriter {
shake256 := sha3.NewCShake256(nil, []byte(heavyHashDomain))
return ShakeHashWriter{shake256}
}
// NewMerkleBranchHashWriter Returns a new HashWriter used for a merkle tree branch

View File

@@ -3,6 +3,7 @@ package hashes
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/pkg/errors"
"golang.org/x/crypto/sha3"
"hash"
)
@@ -30,3 +31,29 @@ func (h HashWriter) Finalize() *externalapi.DomainHash {
copy(sum[:], h.Sum(sum[:0]))
return externalapi.NewDomainHashFromByteArray(&sum)
}
// ShakeHashWriter is exactly the same as HashWriter but for CShake256
type ShakeHashWriter struct {
sha3.ShakeHash
}
// InfallibleWrite is just like write but doesn't return anything
func (h *ShakeHashWriter) InfallibleWrite(p []byte) {
// This write can never return an error, this is part of the hash.Hash interface contract.
_, err := h.Write(p)
if err != nil {
panic(errors.Wrap(err, "this should never happen. sha3.ShakeHash interface promises to not return errors."))
}
}
// Finalize returns the resulting hash
func (h *ShakeHashWriter) Finalize() *externalapi.DomainHash {
var sum [externalapi.DomainHashSize]byte
// This should prevent `Sum` for allocating an output buffer, by using the DomainHash buffer. we still copy because we don't want to rely on that.
_, err := h.Read(sum[:])
if err != nil {
panic(errors.Wrap(err, "this should never happen. sha3.ShakeHash interface promises to not return errors."))
}
h.ShakeHash = nil // prevent double reading as it will return a different hash
return externalapi.NewDomainHashFromByteArray(&sum)
}

View File

@@ -0,0 +1,50 @@
package hashes
import (
"math/rand"
"testing"
)
func BenchmarkNewBlockHashWriterSmall(b *testing.B) {
r := rand.New(rand.NewSource(0))
var someBytes [32]byte
r.Read(someBytes[:])
for i := 0; i < b.N; i++ {
hasher := NewBlockHashWriter()
hasher.InfallibleWrite(someBytes[:])
hasher.Finalize()
}
}
func BenchmarkNewBlockHashWriterBig(b *testing.B) {
r := rand.New(rand.NewSource(0))
var someBytes [1024]byte
r.Read(someBytes[:])
for i := 0; i < b.N; i++ {
hasher := NewBlockHashWriter()
hasher.InfallibleWrite(someBytes[:])
hasher.Finalize()
}
}
func BenchmarkNewHeavyHashWriterSmall(b *testing.B) {
r := rand.New(rand.NewSource(0))
var someBytes [32]byte
r.Read(someBytes[:])
for i := 0; i < b.N; i++ {
hasher := NewHeavyHashWriter()
hasher.InfallibleWrite(someBytes[:])
hasher.Finalize()
}
}
func BenchmarkNewHeavyHashWriterBig(b *testing.B) {
r := rand.New(rand.NewSource(0))
var someBytes [1024]byte
r.Read(someBytes[:])
for i := 0; i < b.N; i++ {
hasher := NewHeavyHashWriter()
hasher.InfallibleWrite(someBytes[:])
hasher.Finalize()
}
}

View File

@@ -6,18 +6,17 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
"github.com/kaspanet/kaspad/util/difficulty"
"github.com/pkg/errors"
)
// SolveBlock increments the given block's nonce until it matches the difficulty requirements in its bits field
func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) {
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
headerForMining := block.Header.ToMutable()
for i := rd.Uint64(); i < math.MaxUint64; i++ {
headerForMining.SetNonce(i)
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
block.Header = headerForMining.ToImmutable()
header := block.Header.ToMutable()
state := pow.NewState(header)
for state.Nonce = rd.Uint64(); state.Nonce < math.MaxUint64; state.Nonce++ {
if state.CheckProofOfWork() {
header.SetNonce(state.Nonce)
block.Header = header.ToImmutable()
return
}
}

View File

@@ -0,0 +1,91 @@
package pow
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"math"
)
const eps float64 = 1e-9
type matrix [64][64]uint16
func generateMatrix(hash *externalapi.DomainHash) *matrix {
var mat matrix
generator := newxoShiRo256PlusPlus(hash)
for {
for i := range mat {
for j := 0; j < 64; j += 16 {
val := generator.Uint64()
for shift := 0; shift < 16; shift++ {
mat[i][j+shift] = uint16(val >> (4 * shift) & 0x0F)
}
}
}
if mat.computeRank() == 64 {
return &mat
}
}
}
func (mat *matrix) computeRank() int {
var B [64][64]float64
for i := range B {
for j := range B[0] {
B[i][j] = float64(mat[i][j])
}
}
var rank int
var rowSelected [64]bool
for i := 0; i < 64; i++ {
var j int
for j := 0; j < 64; j++ {
if !rowSelected[j] && math.Abs(B[j][i]) > eps {
break
}
}
if j != 64 {
rank++
rowSelected[j] = true
for p := i + 1; p < 64; p++ {
B[j][p] /= B[j][i]
}
for k := 0; k < 64; k++ {
if k != j && math.Abs(B[k][i]) > eps {
for p := i + 1; p < 64; p++ {
B[k][p] -= B[j][p] * B[k][i]
}
}
}
}
}
return rank
}
func (mat *matrix) HeavyHash(hash *externalapi.DomainHash) *externalapi.DomainHash {
hashBytes := hash.ByteArray()
var vector [64]uint16
var product [64]uint16
for i := 0; i < 32; i++ {
vector[2*i] = uint16(hashBytes[i] >> 4)
vector[2*i+1] = uint16(hashBytes[i] & 0x0F)
}
// Matrix-vector multiplication, and convert to 4 bits.
for i := 0; i < 64; i++ {
var sum uint16
for j := 0; j < 64; j++ {
sum += mat[i][j] * vector[j]
}
product[i] = sum >> 10
}
// Concatenate 4 LSBs back to 8 bit xor with sum1
var res [32]byte
for i := range res {
res[i] = hashBytes[i] ^ (byte(product[2*i]<<4) | byte(product[2*i+1]))
}
// Hash again
writer := hashes.NewHeavyHashWriter()
writer.InfallibleWrite(res[:])
return writer.Finalize()
}

View File

@@ -0,0 +1,102 @@
package pow
import (
"bytes"
"encoding/hex"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"testing"
)
func BenchmarkMatrix_HeavyHash(b *testing.B) {
input := []byte("BenchmarkMatrix_HeavyHash")
writer := hashes.NewPoWHashWriter()
writer.InfallibleWrite(input)
hash := writer.Finalize()
matrix := generateMatrix(hash)
for i := 0; i < b.N; i++ {
hash = matrix.HeavyHash(hash)
}
}
func TestMatrix_HeavyHash(t *testing.T) {
expected, err := hex.DecodeString("87689f379943eaf9b7475ca95325687772bfcc68fc7899caeb4409ec4590c325")
if err != nil {
t.Fatal(err)
}
input := []byte{0xC1, 0xEC, 0xFD, 0xFC}
writer := hashes.NewPoWHashWriter()
writer.InfallibleWrite(input)
hashed := testMatrix.HeavyHash(writer.Finalize())
if !bytes.Equal(expected, hashed.ByteSlice()) {
t.Fatalf("expected: %x == %s", expected, hashed)
}
}
var testMatrix = matrix{
{13, 2, 14, 13, 2, 15, 14, 3, 10, 4, 1, 8, 4, 3, 8, 15, 15, 15, 15, 15, 2, 11, 15, 15, 15, 1, 7, 12, 12, 4, 2, 0, 6, 1, 14, 10, 12, 14, 15, 8, 10, 12, 0, 5, 13, 3, 14, 10, 10, 6, 12, 11, 11, 7, 6, 6, 10, 2, 2, 4, 11, 12, 0, 5},
{4, 13, 0, 2, 1, 15, 13, 13, 11, 2, 5, 12, 15, 7, 0, 10, 7, 2, 6, 3, 12, 0, 12, 0, 2, 6, 7, 7, 7, 7, 10, 12, 11, 14, 12, 12, 4, 11, 10, 0, 10, 11, 2, 10, 1, 7, 7, 12, 15, 9, 5, 14, 9, 12, 3, 0, 12, 13, 4, 13, 8, 15, 11, 6},
{14, 6, 15, 9, 8, 2, 2, 12, 2, 3, 4, 12, 13, 15, 4, 5, 13, 4, 3, 0, 14, 3, 5, 14, 3, 13, 4, 15, 9, 12, 7, 15, 5, 1, 13, 12, 9, 9, 8, 11, 14, 11, 4, 10, 12, 6, 12, 8, 6, 3, 9, 8, 1, 6, 0, 5, 8, 9, 12, 5, 14, 15, 2, 2},
{9, 6, 7, 6, 0, 11, 5, 6, 2, 14, 12, 6, 4, 13, 8, 9, 2, 1, 9, 7, 4, 5, 10, 8, 11, 11, 11, 15, 7, 11, 1, 14, 3, 8, 14, 8, 2, 8, 13, 7, 8, 8, 15, 7, 1, 13, 7, 9, 1, 7, 15, 15, 0, 0, 12, 15, 13, 5, 13, 10, 1, 5, 6, 13},
{4, 0, 12, 10, 6, 11, 14, 2, 2, 15, 4, 1, 2, 4, 2, 12, 13, 1, 9, 10, 8, 0, 2, 10, 13, 8, 9, 7, 5, 3, 8, 2, 6, 6, 1, 12, 3, 0, 1, 4, 2, 8, 3, 13, 6, 15, 0, 13, 14, 4, 15, 0, 7, 3, 7, 8, 5, 14, 14, 5, 5, 0, 1, 2},
{12, 14, 6, 3, 3, 4, 6, 7, 1, 3, 2, 7, 15, 15, 15, 10, 9, 12, 0, 6, 3, 8, 5, 0, 13, 5, 0, 6, 0, 14, 2, 12, 10, 4, 11, 2, 10, 7, 7, 6, 8, 11, 4, 4, 11, 9, 3, 12, 10, 5, 2, 6, 5, 5, 10, 13, 12, 10, 1, 6, 14, 7, 12, 4},
{7, 14, 6, 7, 7, 12, 4, 1, 8, 6, 8, 13, 13, 5, 12, 14, 10, 8, 6, 2, 12, 3, 8, 15, 5, 15, 15, 3, 14, 0, 8, 6, 9, 12, 9, 7, 3, 8, 4, 0, 7, 14, 3, 3, 13, 14, 3, 7, 3, 2, 2, 3, 3, 12, 6, 7, 4, 1, 14, 10, 6, 10, 2, 9},
{14, 11, 15, 5, 7, 10, 1, 11, 4, 2, 6, 2, 9, 7, 4, 0, 9, 12, 11, 2, 3, 13, 1, 5, 4, 10, 5, 6, 6, 12, 8, 1, 1, 15, 4, 2, 12, 12, 0, 4, 14, 3, 11, 1, 7, 5, 9, 4, 3, 15, 7, 3, 15, 9, 8, 3, 8, 3, 3, 6, 7, 6, 9, 2},
{10, 4, 6, 10, 5, 2, 15, 12, 0, 14, 14, 15, 14, 0, 12, 9, 1, 12, 4, 5, 5, 2, 10, 4, 2, 13, 11, 3, 1, 8, 10, 0, 7, 0, 12, 4, 11, 1, 14, 6, 14, 5, 5, 11, 11, 1, 3, 8, 0, 6, 11, 11, 8, 4, 7, 6, 14, 4, 9, 14, 9, 7, 13, 9},
{12, 7, 9, 8, 2, 3, 3, 5, 14, 8, 0, 9, 7, 4, 2, 15, 15, 3, 11, 11, 8, 5, 7, 5, 0, 15, 10, 8, 0, 13, 1, 14, 8, 10, 1, 4, 13, 1, 13, 3, 11, 11, 2, 3, 10, 6, 8, 14, 15, 2, 10, 10, 12, 7, 7, 6, 6, 3, 13, 8, 1, 14, 2, 1},
{2, 11, 6, 9, 13, 3, 12, 6, 0, 4, 6, 13, 8, 14, 6, 9, 10, 2, 10, 8, 4, 13, 6, 5, 0, 13, 15, 4, 2, 2, 1, 7, 5, 3, 3, 13, 7, 3, 5, 9, 15, 14, 14, 6, 0, 15, 11, 2, 4, 15, 6, 9, 8, 9, 15, 2, 6, 9, 15, 8, 4, 4, 11, 1},
{10, 11, 8, 3, 11, 13, 10, 2, 2, 5, 2, 14, 15, 10, 2, 11, 0, 1, 8, 2, 14, 1, 10, 0, 3, 7, 5, 10, 7, 8, 15, 7, 2, 5, 13, 4, 10, 3, 6, 2, 3, 9, 6, 11, 7, 14, 1, 11, 9, 3, 3, 7, 6, 0, 9, 11, 4, 10, 4, 1, 9, 7, 4, 15},
{13, 8, 15, 14, 11, 12, 5, 3, 9, 14, 1, 5, 14, 13, 14, 5, 13, 5, 4, 10, 9, 9, 0, 0, 6, 12, 5, 7, 2, 7, 2, 6, 6, 6, 1, 12, 9, 15, 7, 11, 11, 10, 11, 1, 10, 10, 0, 8, 1, 4, 5, 5, 8, 10, 10, 15, 6, 8, 13, 11, 11, 3, 15, 5},
{8, 11, 5, 10, 1, 10, 9, 1, 12, 7, 6, 11, 1, 1, 4, 1, 2, 8, 4, 4, 7, 7, 8, 2, 7, 1, 14, 1, 8, 15, 15, 12, 10, 4, 15, 11, 3, 6, 10, 7, 4, 0, 10, 9, 11, 7, 1, 14, 4, 14, 3, 14, 10, 4, 13, 12, 5, 3, 12, 7, 10, 8, 0, 3},
{9, 11, 6, 15, 14, 10, 0, 4, 7, 7, 6, 0, 7, 7, 12, 15, 5, 4, 12, 3, 7, 3, 0, 12, 2, 7, 11, 6, 7, 3, 2, 8, 5, 11, 9, 4, 3, 8, 11, 12, 3, 5, 14, 12, 4, 13, 12, 0, 3, 14, 4, 9, 1, 1, 9, 14, 10, 14, 8, 15, 6, 14, 10, 15},
{10, 14, 10, 0, 10, 12, 15, 0, 3, 9, 11, 10, 3, 5, 1, 1, 9, 1, 7, 15, 7, 8, 10, 10, 12, 11, 5, 1, 10, 3, 6, 6, 13, 0, 13, 1, 4, 5, 9, 4, 9, 15, 8, 4, 13, 13, 4, 5, 5, 11, 1, 13, 15, 3, 10, 15, 7, 11, 10, 15, 8, 12, 10, 3},
{8, 5, 11, 3, 8, 13, 15, 15, 3, 12, 1, 13, 1, 7, 1, 5, 6, 13, 7, 8, 5, 1, 12, 3, 10, 7, 12, 6, 14, 12, 15, 5, 3, 12, 2, 15, 11, 13, 1, 13, 8, 5, 8, 0, 13, 15, 7, 13, 6, 13, 10, 1, 11, 0, 8, 9, 5, 11, 2, 9, 9, 10, 4, 15},
{0, 4, 12, 14, 3, 1, 7, 5, 11, 13, 5, 3, 11, 12, 6, 8, 10, 15, 11, 8, 7, 10, 0, 2, 5, 15, 6, 10, 4, 2, 3, 1, 13, 7, 6, 12, 14, 7, 6, 14, 12, 10, 6, 14, 12, 0, 12, 11, 6, 9, 3, 1, 12, 15, 15, 3, 5, 5, 10, 11, 7, 15, 13, 3},
{12, 14, 2, 14, 13, 6, 15, 7, 8, 8, 14, 13, 9, 2, 2, 10, 3, 15, 6, 10, 11, 7, 13, 0, 12, 1, 5, 8, 8, 12, 1, 11, 1, 3, 2, 4, 10, 7, 7, 7, 3, 10, 7, 2, 2, 3, 0, 1, 13, 5, 8, 2, 14, 0, 11, 13, 9, 3, 13, 2, 14, 2, 15, 4},
{0, 0, 13, 6, 9, 12, 15, 7, 8, 0, 7, 4, 12, 15, 3, 2, 7, 1, 14, 4, 9, 3, 13, 12, 11, 12, 9, 9, 3, 7, 10, 9, 1, 9, 10, 2, 10, 14, 11, 0, 14, 4, 15, 12, 12, 9, 9, 8, 14, 1, 9, 14, 0, 6, 1, 0, 13, 9, 7, 6, 13, 2, 3, 9},
{8, 0, 10, 13, 0, 7, 9, 7, 5, 1, 0, 3, 7, 10, 3, 15, 1, 15, 3, 11, 2, 6, 3, 10, 0, 10, 10, 3, 4, 15, 8, 6, 11, 11, 7, 5, 8, 5, 7, 15, 1, 11, 7, 13, 13, 6, 13, 13, 4, 2, 3, 15, 9, 5, 10, 6, 6, 6, 3, 11, 15, 13, 1, 15},
{1, 1, 2, 10, 2, 2, 9, 5, 9, 2, 0, 1, 14, 2, 11, 6, 11, 6, 1, 0, 13, 7, 14, 1, 15, 14, 13, 7, 12, 11, 8, 11, 2, 11, 6, 10, 2, 3, 0, 0, 15, 0, 4, 6, 4, 12, 5, 5, 7, 14, 10, 6, 0, 3, 13, 0, 8, 1, 13, 10, 5, 1, 7, 5},
{0, 5, 2, 12, 10, 2, 5, 1, 14, 0, 1, 4, 15, 11, 8, 7, 11, 14, 15, 6, 4, 1, 6, 6, 7, 13, 12, 5, 13, 2, 1, 6, 2, 13, 5, 15, 0, 8, 8, 6, 5, 5, 2, 0, 3, 13, 14, 2, 10, 5, 7, 6, 14, 5, 1, 4, 11, 2, 11, 1, 8, 15, 2, 4},
{9, 9, 4, 5, 2, 5, 3, 12, 14, 5, 1, 3, 3, 0, 0, 6, 7, 14, 0, 15, 14, 11, 3, 10, 1, 9, 4, 14, 7, 14, 1, 0, 15, 11, 5, 9, 4, 0, 0, 10, 4, 4, 0, 7, 8, 15, 12, 8, 10, 8, 1, 2, 1, 11, 12, 14, 14, 14, 8, 10, 1, 5, 13, 10},
{5, 10, 4, 4, 11, 10, 0, 6, 0, 12, 10, 5, 9, 11, 8, 10, 11, 3, 11, 14, 12, 9, 4, 6, 11, 12, 8, 7, 6, 14, 0, 6, 12, 4, 5, 3, 9, 0, 11, 6, 1, 3, 2, 12, 8, 9, 7, 12, 14, 7, 12, 6, 11, 13, 0, 2, 1, 3, 1, 8, 12, 2, 15, 15},
{10, 11, 2, 3, 11, 10, 1, 7, 1, 10, 10, 14, 5, 13, 10, 3, 11, 15, 9, 14, 11, 11, 3, 15, 11, 6, 15, 13, 13, 1, 1, 10, 5, 1, 5, 11, 10, 3, 9, 12, 12, 1, 5, 6, 3, 3, 1, 1, 12, 8, 3, 15, 6, 2, 8, 14, 3, 4, 10, 9, 7, 13, 2, 6},
{12, 0, 1, 0, 4, 3, 3, 6, 8, 3, 1, 13, 6, 12, 1, 1, 1, 4, 12, 4, 4, 9, 9, 14, 15, 3, 6, 4, 11, 1, 12, 5, 6, 0, 10, 9, 1, 8, 14, 5, 2, 8, 4, 15, 12, 13, 7, 14, 12, 2, 6, 9, 4, 13, 0, 15, 10, 10, 6, 12, 7, 12, 9, 10},
{0, 8, 5, 11, 12, 12, 11, 7, 2, 9, 2, 15, 1, 1, 0, 0, 6, 5, 10, 1, 11, 12, 8, 7, 1, 7, 10, 4, 2, 8, 2, 5, 1, 1, 2, 9, 2, 0, 3, 7, 5, 1, 5, 5, 3, 1, 4, 3, 14, 8, 11, 7, 8, 0, 2, 13, 3, 15, 1, 13, 14, 15, 11, 13},
{8, 13, 5, 14, 2, 9, 9, 13, 15, 8, 2, 14, 4, 2, 6, 0, 1, 13, 10, 13, 6, 12, 15, 11, 6, 11, 9, 9, 2, 9, 6, 14, 2, 9, 12, 1, 13, 9, 5, 11, 10, 4, 4, 5, 8, 9, 13, 10, 9, 0, 5, 15, 4, 12, 7, 10, 6, 5, 5, 15, 8, 8, 11, 14},
{6, 9, 6, 7, 1, 15, 0, 1, 4, 15, 5, 3, 10, 9, 15, 9, 14, 12, 7, 6, 3, 0, 12, 8, 12, 2, 11, 8, 11, 8, 1, 10, 10, 7, 7, 5, 3, 5, 1, 2, 13, 11, 2, 5, 2, 10, 10, 1, 14, 14, 8, 1, 11, 1, 2, 6, 15, 10, 8, 7, 10, 7, 0, 3},
{12, 6, 11, 1, 1, 7, 8, 1, 5, 5, 8, 4, 6, 5, 6, 4, 2, 8, 4, 1, 0, 0, 14, 2, 10, 14, 14, 11, 2, 9, 14, 15, 12, 14, 9, 3, 7, 14, 4, 7, 12, 9, 3, 5, 1, 0, 12, 9, 10, 5, 11, 12, 10, 10, 6, 14, 6, 13, 13, 5, 5, 10, 13, 10},
{12, 6, 13, 0, 8, 0, 10, 6, 15, 15, 7, 3, 0, 10, 13, 14, 10, 13, 5, 13, 15, 14, 3, 4, 10, 10, 9, 6, 6, 15, 2, 7, 0, 10, 6, 14, 2, 9, 11, 7, 5, 5, 13, 14, 11, 15, 9, 4, 2, 0, 15, 5, 4, 14, 14, 1, 3, 4, 5, 8, 1, 1, 10, 12},
{2, 5, 0, 4, 11, 5, 5, 6, 10, 4, 6, 7, 10, 3, 0, 14, 14, 0, 12, 15, 11, 12, 13, 7, 6, 3, 9, 1, 9, 8, 8, 8, 4, 10, 3, 1, 7, 10, 3, 2, 12, 6, 15, 14, 0, 6, 8, 10, 1, 9, 12, 12, 15, 7, 1, 11, 15, 13, 0, 4, 10, 0, 12, 11},
{8, 12, 14, 15, 14, 15, 10, 0, 2, 14, 3, 1, 2, 6, 0, 2, 1, 7, 9, 0, 15, 13, 5, 14, 6, 8, 15, 4, 15, 6, 10, 6, 15, 3, 12, 8, 5, 4, 10, 5, 3, 0, 4, 13, 10, 9, 8, 4, 6, 3, 9, 6, 12, 11, 9, 13, 8, 10, 9, 9, 8, 12, 1, 2},
{11, 10, 15, 15, 5, 14, 15, 7, 5, 9, 14, 14, 7, 11, 6, 6, 3, 8, 2, 3, 4, 14, 11, 1, 12, 15, 11, 6, 0, 0, 13, 7, 14, 3, 12, 14, 0, 15, 6, 1, 11, 2, 11, 8, 3, 13, 4, 12, 10, 13, 7, 14, 9, 13, 3, 10, 2, 14, 13, 4, 12, 13, 14, 10},
{1, 11, 2, 12, 1, 10, 7, 12, 3, 3, 14, 9, 1, 10, 0, 11, 8, 10, 12, 12, 4, 12, 2, 11, 5, 0, 3, 15, 8, 2, 14, 3, 10, 2, 1, 13, 6, 14, 0, 0, 8, 11, 6, 13, 15, 10, 12, 7, 7, 11, 14, 9, 2, 7, 6, 8, 14, 9, 14, 10, 11, 9, 9, 12},
{5, 10, 14, 2, 1, 4, 11, 5, 10, 2, 13, 9, 6, 12, 11, 5, 13, 4, 5, 14, 8, 7, 15, 9, 8, 4, 5, 2, 9, 11, 5, 3, 12, 2, 6, 1, 7, 4, 11, 4, 15, 0, 5, 2, 13, 11, 11, 2, 15, 10, 0, 12, 5, 8, 10, 1, 4, 11, 3, 13, 11, 7, 9, 14},
{9, 8, 10, 5, 0, 2, 5, 8, 7, 3, 3, 6, 11, 1, 13, 15, 4, 4, 11, 6, 2, 6, 13, 11, 2, 6, 9, 4, 5, 13, 12, 2, 8, 7, 7, 12, 14, 15, 5, 12, 7, 0, 15, 15, 0, 5, 15, 0, 3, 9, 10, 15, 9, 11, 10, 10, 5, 3, 9, 3, 12, 13, 0, 13},
{1, 11, 15, 0, 10, 5, 3, 5, 6, 7, 1, 11, 4, 11, 4, 2, 5, 12, 2, 5, 5, 6, 1, 5, 14, 9, 1, 5, 14, 12, 6, 10, 0, 8, 5, 11, 11, 11, 12, 10, 8, 10, 10, 1, 14, 1, 0, 8, 4, 7, 0, 11, 3, 1, 11, 12, 11, 8, 14, 15, 9, 3, 1, 14},
{14, 11, 12, 12, 4, 6, 8, 14, 15, 1, 11, 2, 13, 3, 6, 2, 7, 1, 8, 1, 4, 9, 11, 15, 8, 1, 10, 13, 4, 13, 2, 7, 7, 10, 5, 2, 12, 12, 12, 3, 10, 8, 2, 11, 0, 3, 8, 9, 4, 2, 15, 7, 15, 6, 4, 6, 12, 7, 14, 9, 9, 8, 14, 12},
{15, 4, 8, 12, 11, 11, 9, 5, 0, 0, 7, 6, 10, 5, 8, 2, 5, 6, 14, 11, 13, 0, 13, 15, 5, 4, 9, 15, 13, 12, 14, 15, 10, 2, 3, 6, 10, 14, 1, 8, 6, 7, 10, 1, 14, 9, 12, 13, 7, 2, 12, 10, 6, 11, 15, 1, 15, 11, 13, 0, 6, 13, 7, 15},
{3, 3, 12, 5, 14, 9, 14, 14, 8, 0, 9, 1, 2, 2, 14, 11, 7, 1, 3, 1, 14, 15, 12, 8, 14, 2, 4, 13, 10, 5, 10, 8, 1, 7, 6, 5, 4, 2, 11, 5, 4, 13, 14, 6, 13, 15, 6, 6, 7, 12, 11, 5, 13, 10, 9, 13, 9, 14, 5, 6, 7, 14, 11, 7},
{14, 12, 11, 5, 0, 5, 10, 5, 7, 1, 7, 11, 1, 0, 13, 6, 5, 14, 3, 0, 5, 14, 6, 7, 8, 5, 8, 6, 6, 3, 6, 1, 8, 3, 10, 7, 15, 6, 11, 6, 6, 7, 13, 2, 2, 0, 0, 11, 1, 15, 2, 14, 5, 1, 4, 8, 0, 1, 8, 0, 1, 1, 2, 2},
{10, 13, 13, 3, 15, 14, 9, 12, 15, 15, 8, 5, 8, 10, 5, 9, 6, 6, 7, 15, 1, 0, 14, 9, 1, 11, 6, 11, 13, 4, 6, 14, 9, 12, 13, 8, 14, 6, 14, 2, 3, 15, 4, 4, 14, 4, 9, 12, 8, 0, 9, 11, 13, 10, 8, 14, 3, 5, 7, 11, 6, 7, 15, 2},
{9, 9, 11, 6, 11, 0, 5, 4, 8, 10, 8, 11, 2, 12, 8, 7, 11, 13, 6, 1, 13, 13, 11, 4, 5, 7, 7, 9, 6, 4, 12, 0, 11, 8, 6, 12, 11, 4, 15, 11, 12, 8, 11, 11, 1, 3, 6, 14, 9, 6, 7, 5, 0, 10, 3, 15, 13, 7, 0, 1, 13, 15, 1, 14},
{10, 6, 8, 7, 3, 6, 9, 15, 1, 3, 10, 14, 9, 0, 0, 10, 0, 15, 2, 0, 0, 0, 6, 0, 13, 9, 9, 1, 8, 6, 13, 2, 1, 9, 14, 9, 1, 4, 8, 4, 2, 0, 8, 5, 0, 11, 12, 15, 13, 1, 14, 14, 15, 7, 8, 4, 4, 12, 1, 12, 8, 3, 9, 5},
{12, 11, 1, 4, 10, 14, 8, 12, 2, 4, 15, 2, 9, 7, 7, 11, 15, 12, 10, 11, 7, 4, 13, 0, 8, 6, 8, 8, 10, 5, 5, 13, 3, 7, 9, 13, 13, 14, 6, 8, 1, 5, 7, 12, 4, 4, 6, 9, 13, 1, 6, 1, 6, 14, 5, 8, 2, 10, 4, 10, 1, 9, 6, 15},
{4, 13, 4, 9, 6, 11, 1, 8, 7, 11, 11, 1, 3, 10, 12, 11, 1, 10, 6, 10, 0, 7, 3, 0, 0, 6, 3, 9, 2, 1, 4, 8, 2, 10, 2, 15, 9, 15, 14, 14, 15, 14, 3, 2, 7, 6, 6, 10, 8, 8, 4, 11, 1, 13, 6, 0, 2, 10, 0, 11, 15, 14, 6, 9},
{15, 0, 12, 13, 0, 9, 10, 4, 11, 5, 10, 0, 8, 7, 3, 2, 12, 6, 3, 8, 5, 15, 14, 2, 13, 13, 6, 11, 5, 6, 9, 10, 14, 5, 14, 4, 9, 7, 5, 11, 13, 2, 7, 1, 14, 9, 0, 7, 8, 12, 11, 15, 2, 1, 5, 11, 3, 7, 5, 1, 6, 3, 8, 6},
{0, 3, 8, 1, 4, 6, 3, 1, 3, 8, 2, 0, 15, 15, 14, 15, 13, 10, 11, 9, 2, 11, 5, 12, 3, 3, 0, 1, 5, 3, 11, 6, 10, 11, 8, 5, 7, 15, 4, 12, 8, 8, 12, 12, 12, 1, 9, 4, 11, 6, 10, 11, 1, 12, 8, 12, 5, 6, 1, 14, 2, 10, 3, 0},
{10, 13, 6, 9, 11, 1, 4, 10, 0, 13, 8, 7, 4, 12, 15, 5, 14, 12, 6, 9, 0, 0, 10, 5, 13, 10, 15, 3, 0, 8, 7, 0, 9, 8, 10, 6, 11, 8, 10, 13, 11, 7, 5, 5, 9, 13, 1, 15, 0, 5, 15, 5, 4, 7, 9, 9, 15, 8, 2, 6, 3, 8, 5, 8},
{14, 0, 6, 2, 4, 12, 2, 13, 6, 10, 5, 2, 2, 1, 6, 11, 1, 6, 9, 13, 0, 13, 9, 3, 12, 4, 3, 8, 7, 0, 9, 12, 0, 1, 7, 10, 10, 7, 3, 9, 13, 5, 15, 4, 13, 0, 8, 5, 4, 14, 11, 3, 3, 13, 15, 9, 9, 12, 9, 5, 2, 0, 1, 14},
{4, 14, 13, 0, 14, 15, 11, 10, 11, 1, 3, 3, 9, 1, 12, 8, 6, 5, 15, 11, 1, 7, 5, 3, 8, 13, 0, 13, 11, 5, 8, 1, 8, 6, 13, 4, 13, 7, 12, 6, 5, 5, 7, 0, 12, 1, 1, 8, 1, 6, 4, 2, 8, 8, 15, 11, 11, 11, 4, 4, 4, 7, 13, 12},
{14, 15, 10, 0, 4, 3, 1, 9, 13, 7, 9, 9, 15, 5, 0, 3, 9, 6, 4, 7, 13, 11, 3, 2, 7, 1, 6, 8, 13, 7, 10, 4, 3, 9, 5, 9, 2, 6, 10, 7, 9, 13, 2, 14, 2, 14, 7, 2, 14, 2, 8, 8, 0, 9, 0, 9, 12, 6, 7, 7, 6, 8, 12, 13},
{5, 15, 8, 12, 11, 3, 13, 4, 5, 14, 10, 4, 15, 15, 1, 10, 9, 14, 6, 6, 4, 12, 4, 9, 12, 2, 15, 13, 2, 5, 12, 2, 3, 2, 15, 11, 12, 2, 6, 2, 11, 6, 7, 9, 12, 10, 5, 1, 1, 5, 9, 6, 14, 11, 3, 11, 6, 10, 11, 11, 0, 12, 15, 1},
{12, 6, 8, 10, 2, 5, 7, 9, 8, 14, 15, 15, 13, 10, 15, 3, 10, 10, 6, 10, 14, 10, 7, 5, 3, 7, 6, 12, 11, 12, 8, 9, 12, 9, 15, 15, 15, 7, 8, 3, 15, 14, 1, 12, 0, 0, 4, 0, 9, 10, 8, 7, 14, 10, 8, 14, 6, 2, 8, 1, 11, 10, 0, 1},
{12, 1, 2, 12, 7, 10, 4, 11, 5, 14, 10, 2, 2, 9, 4, 13, 3, 14, 3, 15, 5, 0, 14, 7, 7, 15, 6, 5, 2, 8, 15, 9, 6, 6, 13, 10, 9, 8, 6, 3, 14, 7, 12, 9, 7, 8, 13, 12, 14, 13, 6, 0, 5, 1, 9, 12, 14, 0, 11, 11, 6, 3, 11, 7},
{15, 4, 8, 12, 8, 11, 4, 15, 1, 6, 2, 13, 1, 7, 7, 12, 0, 8, 14, 14, 10, 14, 0, 12, 0, 3, 3, 11, 7, 4, 2, 13, 0, 0, 11, 2, 5, 8, 12, 11, 6, 5, 6, 0, 0, 4, 0, 0, 1, 9, 9, 11, 3, 2, 13, 4, 13, 9, 15, 4, 7, 8, 3, 2},
{3, 13, 8, 8, 12, 10, 5, 4, 7, 13, 10, 13, 14, 3, 2, 12, 11, 0, 9, 5, 6, 4, 14, 4, 6, 9, 2, 5, 10, 3, 9, 10, 5, 0, 12, 5, 15, 5, 15, 15, 2, 12, 3, 11, 0, 15, 9, 14, 1, 5, 6, 6, 14, 5, 8, 0, 5, 9, 3, 7, 7, 12, 15, 1},
{1, 11, 7, 4, 13, 3, 0, 8, 11, 9, 15, 1, 4, 12, 2, 12, 10, 4, 14, 3, 9, 14, 14, 2, 3, 11, 12, 4, 5, 10, 6, 15, 2, 13, 13, 9, 9, 1, 11, 12, 12, 14, 1, 5, 15, 1, 7, 14, 12, 10, 11, 13, 13, 5, 2, 4, 7, 7, 9, 4, 14, 15, 13, 10},
{14, 15, 9, 14, 9, 5, 13, 2, 0, 0, 14, 8, 6, 2, 0, 7, 11, 10, 2, 13, 2, 14, 9, 6, 4, 11, 5, 14, 6, 1, 6, 14, 6, 3, 9, 5, 2, 9, 3, 11, 1, 14, 5, 4, 12, 5, 3, 5, 11, 3, 11, 6, 13, 7, 13, 7, 4, 9, 4, 13, 8, 3, 5, 11},
{13, 12, 12, 13, 8, 2, 4, 2, 10, 6, 3, 5, 7, 7, 6, 13, 8, 6, 15, 4, 12, 7, 15, 4, 3, 9, 8, 15, 0, 3, 12, 1, 9, 8, 13, 10, 15, 4, 14, 1, 6, 15, 0, 4, 8, 9, 3, 1, 3, 15, 5, 5, 1, 11, 11, 10, 11, 10, 8, 8, 5, 4, 13, 0},
{8, 4, 15, 9, 14, 9, 5, 8, 8, 10, 5, 15, 9, 8, 12, 5, 11, 10, 2, 12, 13, 1, 0, 2, 6, 13, 11, 9, 12, 0, 5, 0, 11, 5, 14, 12, 3, 4, 2, 10, 3, 12, 5, 15, 4, 8, 14, 1, 0, 13, 9, 5, 2, 4, 13, 8, 2, 5, 8, 9, 15, 3, 5, 5},
{0, 3, 3, 4, 6, 5, 5, 1, 3, 2, 14, 5, 10, 7, 15, 11, 7, 13, 15, 4, 0, 12, 9, 15, 12, 0, 3, 1, 14, 1, 12, 9, 13, 8, 9, 15, 12, 3, 5, 11, 3, 11, 4, 1, 9, 4, 13, 7, 4, 10, 6, 14, 13, 0, 9, 11, 15, 15, 3, 3, 13, 15, 10, 15},
}

View File

@@ -12,47 +12,75 @@ import (
"math/big"
)
// CheckProofOfWorkWithTarget check's if the block has a valid PoW according to the provided target
// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network
func CheckProofOfWorkWithTarget(header externalapi.MutableBlockHeader, target *big.Int) bool {
// The block pow must be less than the claimed target
powNum := CalculateProofOfWorkValue(header)
// The block hash must be less or equal than the claimed target.
return powNum.Cmp(target) <= 0
// State is an intermediate data structure with pre-computed values to speed up mining.
type State struct {
mat matrix
Timestamp int64
Nonce uint64
Target big.Int
prePowHash externalapi.DomainHash
}
// CheckProofOfWorkByBits check's if the block has a valid PoW according to its Bits field
// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network
func CheckProofOfWorkByBits(header externalapi.MutableBlockHeader) bool {
return CheckProofOfWorkWithTarget(header, difficulty.CompactToBig(header.Bits()))
}
// CalculateProofOfWorkValue hashes the given header and returns its big.Int value
func CalculateProofOfWorkValue(header externalapi.MutableBlockHeader) *big.Int {
// NewState creates a new state with pre-computed values to speed up mining
// It takes the target from the Bits field
func NewState(header externalapi.MutableBlockHeader) *State {
target := difficulty.CompactToBig(header.Bits())
// Zero out the time and nonce.
timestamp, nonce := header.TimeInMilliseconds(), header.Nonce()
header.SetTimeInMilliseconds(0)
header.SetNonce(0)
prePowHash := consensushashing.HeaderHash(header)
header.SetTimeInMilliseconds(timestamp)
header.SetNonce(nonce)
return &State{
Target: *target,
prePowHash: *prePowHash,
mat: *generateMatrix(prePowHash),
Timestamp: timestamp,
Nonce: nonce,
}
}
// CalculateProofOfWorkValue hashes the internal header and returns its big.Int value
func (state *State) CalculateProofOfWorkValue() *big.Int {
// PRE_POW_HASH || TIME || 32 zero byte padding || NONCE
writer := hashes.NewPoWHashWriter()
writer.InfallibleWrite(prePowHash.ByteSlice())
err := serialization.WriteElement(writer, timestamp)
writer.InfallibleWrite(state.prePowHash.ByteSlice())
err := serialization.WriteElement(writer, state.Timestamp)
if err != nil {
panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error"))
}
zeroes := [32]byte{}
writer.InfallibleWrite(zeroes[:])
err = serialization.WriteElement(writer, nonce)
err = serialization.WriteElement(writer, state.Nonce)
if err != nil {
panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error"))
}
return toBig(writer.Finalize())
powHash := writer.Finalize()
heavyHash := state.mat.HeavyHash(powHash)
return toBig(heavyHash)
}
// IncrementNonce the nonce in State by 1
func (state *State) IncrementNonce() {
state.Nonce++
}
// CheckProofOfWork check's if the block has a valid PoW according to the provided target
// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network
func (state *State) CheckProofOfWork() bool {
// The block pow must be less than the claimed target
powNum := state.CalculateProofOfWorkValue()
// The block hash must be less or equal than the claimed target.
return powNum.Cmp(&state.Target) <= 0
}
// CheckProofOfWorkByBits check's if the block has a valid PoW according to its Bits field
// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network
func CheckProofOfWorkByBits(header externalapi.MutableBlockHeader) bool {
return NewState(header).CheckProofOfWork()
}
// ToBig converts a externalapi.DomainHash into a big.Int treated as a little endian string.
@@ -69,7 +97,13 @@ func toBig(hash *externalapi.DomainHash) *big.Int {
// BlockLevel returns the block level of the given header.
func BlockLevel(header externalapi.BlockHeader) int {
proofOfWorkValue := CalculateProofOfWorkValue(header.ToMutable())
// Genesis is defined to be the root of all blocks at all levels, so we define it to be the maximal
// block level.
if len(header.DirectParents()) == 0 {
return constants.MaxBlockLevel
}
proofOfWorkValue := NewState(header.ToMutable()).CalculateProofOfWorkValue()
for blockLevel := 0; ; blockLevel++ {
if blockLevel == constants.MaxBlockLevel || proofOfWorkValue.Bit(blockLevel+1) != 0 {
return blockLevel

View File

@@ -0,0 +1,37 @@
package pow
import (
"encoding/binary"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"math/bits"
)
type xoShiRo256PlusPlus struct {
s0 uint64
s1 uint64
s2 uint64
s3 uint64
}
func newxoShiRo256PlusPlus(hash *externalapi.DomainHash) *xoShiRo256PlusPlus {
hashArray := hash.ByteArray()
return &xoShiRo256PlusPlus{
s0: binary.LittleEndian.Uint64(hashArray[:8]),
s1: binary.LittleEndian.Uint64(hashArray[8:16]),
s2: binary.LittleEndian.Uint64(hashArray[16:24]),
s3: binary.LittleEndian.Uint64(hashArray[24:32]),
}
}
func (x *xoShiRo256PlusPlus) Uint64() uint64 {
res := bits.RotateLeft64(x.s0+x.s3, 23) + x.s0
t := x.s1 << 17
x.s2 ^= x.s0
x.s3 ^= x.s1
x.s1 ^= x.s2
x.s0 ^= x.s3
x.s2 ^= t
x.s3 = bits.RotateLeft64(x.s3, 45)
return res
}

View File

@@ -0,0 +1,17 @@
package pow
import "testing"
// Test vectors are from here: https://github.com/rust-random/rngs/blob/17aa826cc38d3e8408c9489ac859fa9397acd479/rand_xoshiro/src/xoshiro256plusplus.rs#L121
func TestXoShiRo256PlusPlus_Uint64(t *testing.T) {
state := xoShiRo256PlusPlus{1, 2, 3, 4}
expected := []uint64{41943041, 58720359, 3588806011781223, 3591011842654386,
9228616714210784205, 9973669472204895162, 14011001112246962877,
12406186145184390807, 15849039046786891736, 10450023813501588000}
for _, ex := range expected {
val := state.Uint64()
if val != ex {
t.Errorf("expected: %d, found: %d", ex, val)
}
}
}

View File

@@ -22,7 +22,7 @@ import (
//
const (
defaultMaxCoinbasePayloadLength = 150
defaultMaxCoinbasePayloadLength = 172
// defaultMaxBlockMass is a bound on the mass of a block, larger values increase the bound d
// on the round trip time of a block, which affects the other parameters as described below
defaultMaxBlockMass = 500_000

View File

@@ -19,8 +19,27 @@ var genesisTxPayload = []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score
0x00, 0xE1, 0xF5, 0x05, 0x00, 0x00, 0x00, 0x00, // Subsidy
0x00, 0x00, //script version
0x01, // Varint
0x00, // OP-FALSE
0x01, // Varint
0x00, // OP-FALSE
0xd7, 0x95, 0xd7, 0x9e, 0xd7, 0x94, 0x20, 0xd7, // ומה די עליך ועל אחיך ייטב בשאר כספא ודהבה למעבד כרעות אלהכם תעבדון
0x93, 0xd7, 0x99, 0x20, 0xd7, 0xa2, 0xd7, 0x9c,
0xd7, 0x99, 0xd7, 0x9a, 0x20, 0xd7, 0x95, 0xd7,
0xa2, 0xd7, 0x9c, 0x20, 0xd7, 0x90, 0xd7, 0x97,
0xd7, 0x99, 0xd7, 0x9a, 0x20, 0xd7, 0x99, 0xd7,
0x99, 0xd7, 0x98, 0xd7, 0x91, 0x20, 0xd7, 0x91,
0xd7, 0xa9, 0xd7, 0x90, 0xd7, 0xa8, 0x20, 0xd7,
0x9b, 0xd7, 0xa1, 0xd7, 0xa4, 0xd7, 0x90, 0x20,
0xd7, 0x95, 0xd7, 0x93, 0xd7, 0x94, 0xd7, 0x91,
0xd7, 0x94, 0x20, 0xd7, 0x9c, 0xd7, 0x9e, 0xd7,
0xa2, 0xd7, 0x91, 0xd7, 0x93, 0x20, 0xd7, 0x9b,
0xd7, 0xa8, 0xd7, 0xa2, 0xd7, 0x95, 0xd7, 0xaa,
0x20, 0xd7, 0x90, 0xd7, 0x9c, 0xd7, 0x94, 0xd7,
0x9b, 0xd7, 0x9d, 0x20, 0xd7, 0xaa, 0xd7, 0xa2,
0xd7, 0x91, 0xd7, 0x93, 0xd7, 0x95, 0xd7, 0x9f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Bitcoin block hash 00000000000000000001733c62adb19f1b77fa0735d0e11f25af36fc9ca908a5
0x00, 0x01, 0x73, 0x3c, 0x62, 0xad, 0xb1, 0x9f,
0x1b, 0x77, 0xfa, 0x07, 0x35, 0xd0, 0xe1, 0x1f,
0x25, 0xaf, 0x36, 0xfc, 0x9c, 0xa9, 0x08, 0xa5,
}
// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for
@@ -31,19 +50,19 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, []*externa
// genesisHash is the hash of the first block in the block DAG for the main
// network (genesis block).
var genesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x75, 0xd8, 0x51, 0xcc, 0x91, 0xba, 0x55, 0x32,
0xfd, 0xf9, 0x3e, 0xf2, 0xa5, 0x28, 0x92, 0x83,
0x35, 0xe0, 0x61, 0xa2, 0xe4, 0x77, 0x76, 0x5e,
0xd7, 0x10, 0x5d, 0x8e, 0x78, 0xc7, 0xb8, 0x0d,
0xca, 0xeb, 0x97, 0x96, 0x0a, 0x16, 0x0c, 0x21,
0x1a, 0x6b, 0x21, 0x96, 0xbd, 0x78, 0x39, 0x9f,
0xd4, 0xc4, 0xcc, 0x5b, 0x50, 0x9f, 0x55, 0xc1,
0x2c, 0x8a, 0x7d, 0x81, 0x5f, 0x75, 0x36, 0xea,
})
// genesisMerkleRoot is the hash of the first transaction in the genesis block
// for the main network.
var genesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0xea, 0xb2, 0xe3, 0xfa, 0xd6, 0x72, 0x95, 0x38,
0x04, 0xe0, 0x43, 0x1a, 0xf2, 0x2d, 0xc5, 0xeb,
0x27, 0xd8, 0x0a, 0xdd, 0x4c, 0xc5, 0xd9, 0x80,
0x90, 0xc7, 0x6c, 0x43, 0xce, 0x81, 0x23, 0x68,
0xca, 0xed, 0xaf, 0x7d, 0x4a, 0x08, 0xbb, 0xe8,
0x90, 0x11, 0x64, 0x0c, 0x48, 0x41, 0xb6, 0x6d,
0x5b, 0xba, 0x67, 0xd7, 0x28, 0x8c, 0xe6, 0xd6,
0x72, 0x28, 0xdb, 0x00, 0x09, 0x66, 0xe9, 0x74,
})
// genesisBlock defines the genesis block of the block DAG which serves as the
@@ -55,9 +74,9 @@ var genesisBlock = externalapi.DomainBlock{
genesisMerkleRoot,
&externalapi.DomainHash{},
externalapi.NewDomainHashFromByteArray(muhash.EmptyMuHashHash.AsArray()),
0x17c2df949fe,
0x207fffff,
0x0,
0x17cfb020c02,
0x1e7fffff,
0x3392c,
0,
0,
big.NewInt(0),
@@ -86,10 +105,10 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0,
// devGenesisHash is the hash of the first block in the block DAG for the development
// network (genesis block).
var devnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0xf1, 0xa4, 0x65, 0xfe, 0xd2, 0x08, 0x54, 0xc1,
0x72, 0x60, 0xdc, 0x8b, 0x29, 0x67, 0x90, 0x1f,
0xa9, 0x48, 0x47, 0x4e, 0x63, 0xa1, 0xfc, 0x09,
0x6d, 0x10, 0x7b, 0x08, 0x23, 0x37, 0xfd, 0x59,
0x34, 0x3b, 0x53, 0xb7, 0xad, 0x82, 0x8a, 0x33,
0x4b, 0x03, 0xb1, 0xbb, 0x13, 0x15, 0xb0, 0x75,
0xf3, 0xf0, 0x40, 0xfb, 0x64, 0x0c, 0xca, 0x19,
0xc9, 0x61, 0xe7, 0x69, 0xdb, 0x98, 0x98, 0x3e,
})
// devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block
@@ -112,7 +131,7 @@ var devnetGenesisBlock = externalapi.DomainBlock{
externalapi.NewDomainHashFromByteArray(muhash.EmptyMuHashHash.AsArray()),
0x11e9db49828,
0x1e7fffff,
0x268db,
0x48e5e,
0,
0,
big.NewInt(0),
@@ -140,10 +159,10 @@ var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0,
// simnetGenesisHash is the hash of the first block in the block DAG for
// the simnet (genesis block).
var simnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x9b, 0x66, 0xc8, 0x1a, 0xd5, 0xb8, 0xc2, 0xf7,
0x45, 0x45, 0x47, 0xd6, 0x83, 0x83, 0xf8, 0x27,
0x45, 0x46, 0xcf, 0x98, 0x1c, 0x74, 0x46, 0xcf,
0x25, 0x5e, 0xd3, 0xe7, 0xe4, 0x68, 0x47, 0x6f,
0x41, 0x1f, 0x8c, 0xd2, 0x6f, 0x3d, 0x41, 0xae,
0xa3, 0x9e, 0x78, 0x57, 0x39, 0x27, 0xda, 0x24,
0xd2, 0x39, 0x95, 0x70, 0x5b, 0x57, 0x9f, 0x30,
0x95, 0x9b, 0x91, 0x27, 0xe9, 0x6b, 0x79, 0xe3,
})
// simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block
@@ -164,9 +183,9 @@ var simnetGenesisBlock = externalapi.DomainBlock{
simnetGenesisMerkleRoot,
&externalapi.DomainHash{},
externalapi.NewDomainHashFromByteArray(muhash.EmptyMuHashHash.AsArray()),
0x17c2df94abb,
0x17c5f62fbb6,
0x207fffff,
0x0,
0x2,
0,
0,
big.NewInt(0),
@@ -194,10 +213,10 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0,
// testnetGenesisHash is the hash of the first block in the block DAG for the test
// network (genesis block).
var testnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
0x47, 0x4f, 0xfd, 0xd1, 0xf8, 0x3d, 0x1d, 0x00,
0xcb, 0x07, 0x17, 0x91, 0x56, 0x60, 0xd4, 0xa7,
0x27, 0x5e, 0x43, 0xc2, 0x74, 0xe6, 0x76, 0x6e,
0x34, 0xe4, 0x13, 0xbb, 0x24, 0x02, 0x30, 0x66,
0xf8, 0x96, 0xa3, 0x03, 0x48, 0x73, 0xbe, 0x17,
0x39, 0xfc, 0x43, 0x59, 0x23, 0x68, 0x99, 0xfd,
0x3d, 0x65, 0xd2, 0xbc, 0x94, 0xf9, 0x78, 0x0d,
0xf0, 0xd0, 0xda, 0x3e, 0xb1, 0xcc, 0x43, 0x70,
})
// testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block
@@ -218,9 +237,9 @@ var testnetGenesisBlock = externalapi.DomainBlock{
testnetGenesisMerkleRoot,
&externalapi.DomainHash{},
externalapi.NewDomainHashFromByteArray(muhash.EmptyMuHashHash.AsArray()),
0x17c2df94abb,
0x17c5f62fbb6,
0x1e7fffff,
0x35f16,
0x14582,
0,
0,
big.NewInt(0),

View File

@@ -185,7 +185,7 @@ type Params struct {
FixedSubsidySwitchPruningPointInterval uint64
FixedSubsidySwitchHashRateDifference *big.Int
FixedSubsidySwitchHashRateThreshold *big.Int
}
// NormalizeRPCServerAddress returns addr with the current network default
@@ -211,6 +211,7 @@ var MainnetParams = Params{
Net: appmessage.Mainnet,
RPCPort: "16110",
DefaultPort: "16111",
DNSSeeds: []string{"mainnet-dnsseed.daglabs-dev.com"},
// DAG parameters
GenesisBlock: &genesisBlock,
@@ -262,7 +263,7 @@ var MainnetParams = Params{
CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength,
PruningProofM: defaultPruningProofM,
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
FixedSubsidySwitchHashRateDifference: big.NewInt(1_000_000),
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
}
// TestnetParams defines the network parameters for the test Kaspa network.
@@ -324,7 +325,7 @@ var TestnetParams = Params{
CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength,
PruningProofM: defaultPruningProofM,
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
FixedSubsidySwitchHashRateDifference: big.NewInt(1_000_000),
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
}
// SimnetParams defines the network parameters for the simulation test Kaspa
@@ -390,7 +391,7 @@ var SimnetParams = Params{
CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength,
PruningProofM: defaultPruningProofM,
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
FixedSubsidySwitchHashRateDifference: big.NewInt(1_000_000),
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
}
// DevnetParams defines the network parameters for the development Kaspa network.
@@ -452,7 +453,7 @@ var DevnetParams = Params{
CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength,
PruningProofM: defaultPruningProofM,
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
FixedSubsidySwitchHashRateDifference: big.NewInt(1_000_000),
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
}
var (

View File

@@ -81,10 +81,6 @@ func (networkFlags *NetworkFlags) ResolveNetwork(parser *flags.Parser) error {
return err
}
if numNets == 0 {
return errors.Errorf("Mainnet has not launched yet, use --testnet to run in testnet mode")
}
err := networkFlags.overrideDAGParams()
if err != nil {
return err

View File

@@ -18,7 +18,7 @@ type p2pServer struct {
gRPCServer
}
const p2pMaxMessageSize = 100 * 1024 * 1024 // 100MB
const p2pMaxMessageSize = 1024 * 1024 * 1024 // 1GB
// p2pMaxInboundConnections is the max amount of inbound connections for the P2P server.
// Note that inbound connections are not limited by the gRPC server. (A value of 0 means

View File

@@ -7,9 +7,7 @@ import (
"github.com/kaspanet/kaspad/domain/dagconfig"
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
"github.com/kaspanet/kaspad/stability-tests/common"
"github.com/kaspanet/kaspad/util/difficulty"
"math"
"math/big"
"math/rand"
"os"
"testing"
@@ -162,17 +160,15 @@ func measureMachineHashNanoseconds(t *testing.T) int64 {
defer t.Logf("Finished measuring machine hash rate")
genesisBlock := dagconfig.DevnetParams.GenesisBlock
targetDifficulty := difficulty.CompactToBig(genesisBlock.Header.Bits())
headerForMining := genesisBlock.Header.ToMutable()
state := pow.NewState(genesisBlock.Header.ToMutable())
machineHashesPerSecondMeasurementDuration := 10 * time.Second
hashes := int64(0)
nonce := rand.Uint64()
state.Nonce = rand.Uint64()
loopForDuration(machineHashesPerSecondMeasurementDuration, func(isFinished *bool) {
headerForMining.SetNonce(nonce)
pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty)
state.CheckProofOfWork()
hashes++
nonce++
state.IncrementNonce()
})
return machineHashesPerSecondMeasurementDuration.Nanoseconds() / hashes
@@ -202,17 +198,18 @@ func runDAATest(t *testing.T, testName string, runDuration time.Duration,
startTime := time.Now()
loopForDuration(runDuration, func(isFinished *bool) {
templateBlock := fetchBlockForMining(t, rpcClient)
targetDifficulty := difficulty.CompactToBig(templateBlock.Header.Bits())
headerForMining := templateBlock.Header.ToMutable()
minerState := pow.NewState(headerForMining)
// Try hashes until we find a valid block
miningStartTime := time.Now()
nonce := rand.Uint64()
minerState.Nonce = rand.Uint64()
for {
hashStartTime := time.Now()
blockFound := tryNonceForMiningAndIncrementNonce(headerForMining, &nonce, targetDifficulty, templateBlock)
if blockFound {
if minerState.CheckProofOfWork() {
headerForMining.SetNonce(minerState.Nonce)
templateBlock.Header = headerForMining.ToImmutable()
break
}
@@ -227,6 +224,7 @@ func runDAATest(t *testing.T, testName string, runDuration time.Duration,
if *isFinished {
return
}
minerState.IncrementNonce()
}
// Collect stats about block rate
@@ -265,19 +263,6 @@ func fetchBlockForMining(t *testing.T, rpcClient *rpcclient.RPCClient) *external
return templateBlock
}
func tryNonceForMiningAndIncrementNonce(headerForMining externalapi.MutableBlockHeader, nonce *uint64,
targetDifficulty *big.Int, templateBlock *externalapi.DomainBlock) bool {
headerForMining.SetNonce(*nonce)
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
templateBlock.Header = headerForMining.ToImmutable()
return true
}
*nonce++
return false
}
func waitUntilTargetHashDurationHadElapsed(startTime time.Time, hashStartTime time.Time,
targetHashNanosecondsFunction func(totalElapsedDuration time.Duration) int64) {

View File

@@ -4,11 +4,9 @@ import (
"fmt"
"github.com/kaspanet/go-secp256k1"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/difficulty"
"math"
"math/rand"
"os"
"os/exec"
"strings"
@@ -78,8 +76,8 @@ func realMain() error {
genesisTimestamp := activeConfig().NetParams().GenesisBlock.Header.TimeInMilliseconds()
mutableHeader.SetTimeInMilliseconds(genesisTimestamp + 1000)
block.Header = mutableHeader.ToImmutable()
solvedBlock := solveBlock(block)
_, err = rpcClient.SubmitBlock(solvedBlock)
mining.SolveBlock(block, rand.New(rand.NewSource(time.Now().UnixNano())))
_, err = rpcClient.SubmitBlock(block)
if err != nil {
return err
}
@@ -183,8 +181,8 @@ func mineBlock(rpcClient *rpc.Client, miningAddress util.Address) error {
if err != nil {
return err
}
solvedBlock := solveBlock(block)
_, err = rpcClient.SubmitBlock(solvedBlock)
mining.SolveBlock(block, rand.New(rand.NewSource(time.Now().UnixNano())))
_, err = rpcClient.SubmitBlock(block)
if err != nil {
return err
}
@@ -200,9 +198,10 @@ func mineTips(numOfTips int, miningAddress util.Address, rpcClient *rpc.Client)
if err != nil {
return err
}
rd := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < numOfTips; i++ {
solvedBlock := solveBlock(block)
_, err = rpcClient.SubmitBlock(solvedBlock)
mining.SolveBlock(block, rd)
_, err = rpcClient.SubmitBlock(block)
if err != nil {
return err
}
@@ -296,23 +295,6 @@ func getCurrentTipsLength(rpcClient *rpc.Client) (int, error) {
return len(dagInfo.TipHashes), nil
}
var latestNonce uint64 = 0 // Use to make the nonce unique.
// The nonce is unique for each block in this function.
func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock {
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
headerForMining := block.Header.ToMutable()
maxUInt64 := uint64(math.MaxUint64)
for i := latestNonce; i < maxUInt64; i++ {
headerForMining.SetNonce(i)
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
block.Header = headerForMining.ToImmutable()
latestNonce = i + 1
return block
}
}
panic("Failed to solve block!")
}
func killWithSigterm(cmd *exec.Cmd, commandName string) {
err := cmd.Process.Signal(syscall.SIGTERM)
if err != nil {

View File

@@ -3,6 +3,8 @@ package integration
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
"math/rand"
"reflect"
"sync"
"testing"
@@ -117,7 +119,7 @@ func TestIBDWithPruning(t *testing.T) {
}
// This should trigger resolving the syncee virtual
syncerTip := mineNextBlockWithMockTimestamps(t, syncer)
syncerTip := mineNextBlockWithMockTimestamps(t, syncer, rand.New(rand.NewSource(time.Now().UnixNano())))
time.Sleep(time.Second)
synceeSelectedTip, err := syncee.rpcClient.GetSelectedTipHash()
if err != nil {
@@ -184,12 +186,13 @@ func TestIBDWithPruning(t *testing.T) {
// iteration to find the highest shared chain
// block.
const synceeOnlyBlocks = 2
rd := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < synceeOnlyBlocks; i++ {
mineNextBlockWithMockTimestamps(t, syncee1)
mineNextBlockWithMockTimestamps(t, syncee1, rd)
}
for i := 0; i < numBlocks-1; i++ {
mineNextBlockWithMockTimestamps(t, syncer)
mineNextBlockWithMockTimestamps(t, syncer, rd)
}
testSync(syncer, syncee1)
@@ -203,7 +206,7 @@ var currentMockTimestamp int64 = 0
// mineNextBlockWithMockTimestamps mines blocks with large timestamp differences
// between every two blocks. This is done to avoid the timestamp threshold validation
// of ibd-with-headers-proof
func mineNextBlockWithMockTimestamps(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
func mineNextBlockWithMockTimestamps(t *testing.T, harness *appHarness, rd *rand.Rand) *externalapi.DomainBlock {
blockTemplate, err := harness.rpcClient.GetBlockTemplate(harness.miningAddress)
if err != nil {
t.Fatalf("Error getting block template: %+v", err)
@@ -223,7 +226,7 @@ func mineNextBlockWithMockTimestamps(t *testing.T, harness *appHarness) *externa
mutableHeader.SetTimeInMilliseconds(currentMockTimestamp)
block.Header = mutableHeader.ToImmutable()
solveBlock(block)
mining.SolveBlock(block, rd)
_, err = harness.rpcClient.SubmitBlock(block)
if err != nil {

View File

@@ -3,28 +3,13 @@ package integration
import (
"math/rand"
"testing"
"time"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
"github.com/kaspanet/kaspad/util/difficulty"
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
)
func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock {
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
headerForMining := block.Header.ToMutable()
initialNonce := rand.Uint64()
for i := initialNonce; i != initialNonce-1; i++ {
headerForMining.SetNonce(i)
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
block.Header = headerForMining.ToImmutable()
return block
}
}
panic("Failed to solve block! This should never happen")
}
func mineNextBlock(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
blockTemplate, err := harness.rpcClient.GetBlockTemplate(harness.miningAddress)
if err != nil {
@@ -36,7 +21,8 @@ func mineNextBlock(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
t.Fatalf("Error converting block: %s", err)
}
solveBlock(block)
rd := rand.New(rand.NewSource(time.Now().UnixNano()))
mining.SolveBlock(block, rd)
_, err = harness.rpcClient.SubmitBlock(block)
if err != nil {

View File

@@ -14,7 +14,7 @@ import (
func TestGetHashrateString(t *testing.T) {
var results = map[string]string{
dagconfig.MainnetParams.Name: "2 H/s",
dagconfig.MainnetParams.Name: "131.07 KH/s",
dagconfig.TestnetParams.Name: "131.07 KH/s",
dagconfig.DevnetParams.Name: "131.07 KH/s",
dagconfig.SimnetParams.Name: "2.00 KH/s",

View File

@@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
const (
appMajor uint = 0
appMinor uint = 11
appPatch uint = 0
appPatch uint = 2
)
// appBuild is defined as a variable so it can be overridden during the build