mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-02-22 19:45:36 +00:00
Compare commits
13 Commits
mainnet-dn
...
v0.11.3-ti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8d36a1772 | ||
|
|
5c1ba9170e | ||
|
|
9d8c555bdf | ||
|
|
a2f574eab8 | ||
|
|
7bed86dc1b | ||
|
|
9b81f5145e | ||
|
|
cd8341ef57 | ||
|
|
ad8bdbed21 | ||
|
|
7cdceb6df0 | ||
|
|
cc5248106e | ||
|
|
e3463b7268 | ||
|
|
a2173ef80a | ||
|
|
aeb4500b61 |
8
.github/workflows/deploy.yaml
vendored
8
.github/workflows/deploy.yaml
vendored
@@ -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/*
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
// DefaultTimeout is the default duration to wait for enqueuing/dequeuing
|
||||
// to/from routes.
|
||||
const DefaultTimeout = 30 * time.Second
|
||||
const DefaultTimeout = 120 * time.Second
|
||||
|
||||
// ErrPeerWithSameIDExists signifies that a peer with the same ID already exist.
|
||||
var ErrPeerWithSameIDExists = errors.New("ready peer with the same ID already exists")
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -102,9 +102,30 @@ func (bp *blockProcessor) validateAndInsertBlock(stagingArea *model.StagingArea,
|
||||
}
|
||||
}
|
||||
|
||||
err = bp.headerTipsManager.AddHeaderTip(stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
shouldAddHeaderSelectedTip := false
|
||||
if !hasHeaderSelectedTip {
|
||||
shouldAddHeaderSelectedTip = true
|
||||
} else {
|
||||
pruningPoint, err := bp.pruningStore.PruningPoint(bp.databaseContext, stagingArea)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isInSelectedChainOfPruningPoint, err := bp.dagTopologyManager.IsInSelectedParentChainOf(stagingArea, pruningPoint, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Don't set blocks in the anticone of the pruning point as header selected tip.
|
||||
shouldAddHeaderSelectedTip = isInSelectedChainOfPruningPoint
|
||||
}
|
||||
|
||||
if shouldAddHeaderSelectedTip {
|
||||
// Don't set blocks in the anticone of the pruning point as header selected tip.
|
||||
err = bp.headerTipsManager.AddHeaderTip(stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var selectedParentChainChanges *externalapi.SelectedChainPath
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
50
domain/consensus/utils/hashes/writers_test.go
Normal file
50
domain/consensus/utils/hashes/writers_test.go
Normal 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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
91
domain/consensus/utils/pow/heavyhash.go
Normal file
91
domain/consensus/utils/pow/heavyhash.go
Normal 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()
|
||||
}
|
||||
233
domain/consensus/utils/pow/heavyhash_test.go
Normal file
233
domain/consensus/utils/pow/heavyhash_test.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package pow
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||
"math/rand"
|
||||
"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 BenchmarkMatrix_Generate(b *testing.B) {
|
||||
r := rand.New(rand.NewSource(0))
|
||||
h := [32]byte{}
|
||||
r.Read(h[:])
|
||||
hash := externalapi.NewDomainHashFromByteArray(&h)
|
||||
for i := 0; i < b.N; i++ {
|
||||
generateMatrix(hash)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatrix_Rank(b *testing.B) {
|
||||
r := rand.New(rand.NewSource(0))
|
||||
h := [32]byte{}
|
||||
r.Read(h[:])
|
||||
hash := externalapi.NewDomainHashFromByteArray(&h)
|
||||
matrix := generateMatrix(hash)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
matrix.computeRank()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatrix_Rank(t *testing.T) {
|
||||
var mat matrix
|
||||
if mat.computeRank() != 0 {
|
||||
t.Fatalf("The zero matrix should have rank 0, instead got: %d", mat.computeRank())
|
||||
}
|
||||
|
||||
r := rand.New(rand.NewSource(0))
|
||||
h := [32]byte{}
|
||||
r.Read(h[:])
|
||||
hash := externalapi.NewDomainHashFromByteArray(&h)
|
||||
mat = *generateMatrix(hash)
|
||||
|
||||
if mat.computeRank() != 64 {
|
||||
t.Fatalf("generateMatrix() should always return full rank matrix, instead got: %d", mat.computeRank())
|
||||
}
|
||||
|
||||
for i := range mat {
|
||||
mat[0][i] = mat[1][i] * 2
|
||||
}
|
||||
if mat.computeRank() != 63 {
|
||||
t.Fatalf("Made a linear depenency between 2 rows, rank should be 63, instead got: %d", mat.computeRank())
|
||||
}
|
||||
|
||||
for i := range mat {
|
||||
mat[33][i] = mat[32][i] * 3
|
||||
}
|
||||
if mat.computeRank() != 62 {
|
||||
t.Fatalf("Made anoter linear depenency between 2 rows, rank should be 62, instead got: %d", mat.computeRank())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateMatrix(t *testing.T) {
|
||||
hashBytes := [32]byte{42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42}
|
||||
hash := externalapi.NewDomainHashFromByteArray(&hashBytes)
|
||||
expectedMatrix := matrix{
|
||||
{4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 2, 10, 2, 10, 2, 10, 2, 10, 2, 10, 2, 10, 2, 10, 2, 10, 14, 1, 2, 2, 14, 10, 4, 12, 4, 12, 10, 10, 10, 10, 10, 10},
|
||||
{9, 11, 1, 11, 1, 11, 9, 11, 9, 11, 9, 3, 12, 13, 11, 5, 15, 15, 5, 0, 6, 8, 1, 8, 6, 11, 15, 5, 3, 6, 7, 3, 2, 15, 14, 3, 7, 11, 14, 7, 3, 6, 14, 12, 3, 9, 5, 1, 1, 0, 8, 4, 10, 15, 9, 10, 6, 13, 1, 1, 7, 4, 4, 6},
|
||||
{2, 6, 0, 8, 11, 15, 4, 0, 5, 2, 7, 13, 15, 3, 11, 12, 6, 2, 1, 8, 13, 4, 11, 4, 10, 14, 13, 2, 6, 15, 10, 6, 6, 5, 6, 9, 3, 3, 3, 1, 9, 12, 12, 15, 6, 0, 1, 5, 7, 13, 14, 1, 10, 10, 5, 14, 4, 0, 12, 13, 2, 15, 8, 4},
|
||||
{8, 6, 5, 1, 0, 6, 4, 8, 13, 0, 8, 12, 7, 2, 4, 3, 10, 5, 9, 3, 12, 13, 2, 4, 13, 14, 7, 7, 9, 12, 10, 8, 11, 6, 14, 3, 12, 8, 8, 0, 2, 10, 0, 9, 1, 9, 7, 8, 5, 2, 9, 13, 15, 6, 13, 10, 1, 9, 1, 10, 6, 2, 10, 9},
|
||||
{4, 2, 6, 14, 4, 2, 5, 7, 15, 6, 0, 4, 11, 9, 12, 0, 3, 2, 0, 4, 10, 5, 12, 3, 3, 4, 10, 1, 0, 13, 3, 12, 15, 0, 7, 10, 2, 2, 15, 0, 2, 15, 8, 2, 15, 12, 10, 6, 6, 2, 13, 3, 8, 14, 3, 13, 10, 5, 4, 5, 1, 6, 5, 10},
|
||||
{0, 3, 13, 12, 11, 4, 11, 13, 1, 12, 4, 11, 15, 14, 13, 4, 7, 1, 3, 0, 10, 3, 8, 8, 1, 2, 5, 14, 4, 5, 14, 1, 1, 3, 3, 1, 5, 15, 7, 5, 11, 8, 8, 12, 10, 5, 7, 9, 2, 10, 13, 11, 4, 2, 12, 15, 10, 6, 6, 0, 6, 6, 3, 12},
|
||||
{9, 12, 3, 3, 5, 8, 12, 13, 7, 4, 5, 11, 4, 0, 7, 2, 2, 15, 12, 14, 12, 5, 4, 2, 8, 8, 8, 13, 6, 1, 1, 5, 0, 15, 12, 13, 8, 5, 0, 4, 13, 1, 6, 1, 12, 14, 1, 0, 13, 12, 10, 10, 1, 4, 13, 13, 8, 4, 15, 13, 6, 6, 14, 10},
|
||||
{14, 15, 8, 0, 7, 2, 5, 10, 5, 3, 12, 0, 11, 3, 4, 2, 8, 11, 6, 14, 14, 3, 3, 12, 3, 7, 6, 2, 6, 12, 15, 1, 1, 13, 0, 6, 9, 9, 7, 7, 13, 4, 4, 2, 15, 5, 2, 15, 13, 13, 10, 6, 9, 15, 2, 9, 6, 10, 6, 14, 14, 3, 5, 11},
|
||||
{6, 4, 7, 8, 11, 0, 13, 11, 0, 7, 0, 0, 13, 6, 3, 11, 15, 14, 10, 2, 7, 8, 13, 14, 8, 15, 10, 8, 14, 6, 10, 14, 3, 11, 5, 11, 13, 5, 3, 12, 3, 0, 2, 0, 6, 14, 4, 12, 4, 4, 8, 15, 7, 8, 12, 11, 3, 9, 5, 13, 10, 14, 13, 4},
|
||||
{10, 0, 0, 15, 1, 4, 13, 3, 15, 10, 2, 5, 11, 2, 9, 14, 7, 3, 2, 8, 6, 15, 0, 12, 1, 4, 1, 9, 3, 0, 15, 8, 9, 13, 0, 7, 9, 10, 6, 14, 3, 7, 9, 7, 4, 0, 11, 8, 4, 6, 5, 8, 8, 0, 5, 14, 7, 12, 12, 2, 5, 6, 5, 6},
|
||||
{12, 0, 0, 14, 8, 3, 0, 3, 13, 10, 5, 13, 5, 7, 2, 4, 13, 11, 3, 1, 11, 2, 14, 5, 10, 5, 5, 9, 12, 15, 12, 8, 1, 0, 11, 13, 8, 1, 1, 11, 10, 0, 11, 15, 13, 9, 12, 14, 5, 4, 5, 14, 2, 7, 2, 1, 4, 12, 11, 11, 9, 12, 11, 15},
|
||||
{3, 15, 9, 8, 13, 12, 15, 7, 8, 7, 14, 6, 10, 3, 0, 5, 2, 2, 6, 6, 3, 2, 5, 12, 11, 2, 10, 11, 13, 3, 9, 7, 7, 6, 8, 15, 14, 14, 11, 11, 9, 7, 1, 3, 8, 5, 11, 11, 1, 2, 15, 8, 13, 8, 11, 4, 1, 5, 3, 12, 5, 3, 7, 7},
|
||||
{13, 13, 2, 14, 4, 3, 15, 2, 0, 15, 1, 5, 4, 1, 5, 1, 4, 14, 5, 1, 11, 13, 15, 1, 3, 3, 5, 13, 14, 1, 0, 4, 6, 1, 15, 7, 7, 0, 15, 8, 15, 3, 14, 7, 7, 8, 12, 10, 2, 14, 9, 2, 11, 11, 7, 10, 4, 3, 12, 13, 4, 13, 0, 14},
|
||||
{12, 14, 15, 15, 2, 0, 0, 13, 4, 6, 4, 2, 14, 11, 5, 6, 14, 8, 14, 7, 13, 15, 6, 15, 7, 9, 1, 0, 11, 9, 9, 0, 2, 12, 8, 8, 14, 11, 7, 5, 3, 0, 11, 12, 9, 2, 8, 9, 0, 0, 9, 8, 9, 8, 2, 14, 12, 2, 0, 14, 13, 8, 4, 10},
|
||||
{7, 10, 1, 15, 12, 14, 7, 4, 7, 13, 4, 8, 13, 12, 1, 7, 10, 6, 5, 14, 14, 3, 14, 4, 11, 14, 6, 12, 15, 12, 15, 12, 4, 5, 9, 8, 7, 7, 3, 0, 5, 7, 3, 8, 4, 4, 7, 5, 6, 12, 13, 0, 12, 10, 2, 5, 14, 9, 6, 4, 13, 13, 14, 5},
|
||||
{14, 5, 8, 3, 4, 15, 13, 14, 14, 10, 7, 14, 15, 2, 11, 14, 13, 13, 12, 10, 6, 9, 5, 5, 6, 13, 15, 13, 7, 0, 15, 11, 4, 12, 15, 7, 7, 4, 3, 11, 8, 14, 5, 10, 2, 4, 4, 12, 3, 6, 1, 9, 15, 1, 1, 13, 7, 5, 0, 14, 15, 7, 8, 6},
|
||||
{1, 2, 10, 5, 2, 13, 1, 11, 15, 10, 4, 9, 9, 12, 14, 13, 3, 5, 0, 3, 7, 11, 10, 3, 12, 5, 10, 2, 13, 7, 1, 7, 13, 8, 2, 8, 3, 14, 10, 3, 5, 12, 0, 9, 3, 9, 11, 2, 10, 9, 0, 6, 4, 0, 1, 14, 11, 0, 8, 6, 1, 15, 3, 10},
|
||||
{13, 9, 0, 5, 8, 7, 12, 15, 10, 10, 5, 1, 1, 7, 6, 1, 14, 5, 15, 2, 3, 5, 3, 5, 7, 3, 7, 7, 1, 4, 3, 14, 5, 0, 12, 0, 12, 10, 10, 6, 12, 6, 3, 5, 5, 11, 10, 1, 11, 3, 13, 3, 9, 11, 1, 7, 14, 14, 0, 8, 15, 5, 2, 7},
|
||||
{8, 5, 11, 6, 15, 0, 1, 13, 1, 6, 7, 15, 4, 3, 14, 12, 9, 3, 11, 6, 4, 12, 1, 11, 6, 12, 5, 11, 1, 12, 2, 3, 1, 2, 11, 12, 0, 5, 11, 5, 3, 13, 11, 3, 11, 14, 10, 8, 3, 9, 4, 8, 13, 11, 9, 11, 2, 4, 12, 3, 0, 14, 7, 11},
|
||||
{10, 11, 4, 10, 7, 8, 3, 14, 15, 8, 15, 6, 9, 8, 5, 6, 12, 1, 15, 6, 5, 5, 14, 13, 2, 12, 14, 6, 5, 5, 14, 9, 1, 10, 11, 14, 8, 6, 14, 11, 1, 15, 6, 11, 11, 8, 1, 2, 8, 5, 4, 15, 6, 8, 0, 8, 0, 11, 0, 1, 0, 7, 8, 15},
|
||||
{0, 15, 5, 0, 11, 4, 4, 2, 0, 4, 8, 12, 2, 2, 0, 8, 1, 2, 6, 5, 6, 12, 3, 1, 12, 1, 6, 10, 2, 5, 0, 2, 0, 11, 8, 6, 13, 4, 14, 4, 15, 5, 8, 11, 9, 6, 2, 6, 9, 1, 4, 2, 14, 10, 4, 4, 1, 1, 11, 8, 6, 11, 11, 9},
|
||||
{7, 3, 6, 5, 9, 1, 11, 0, 15, 13, 13, 13, 4, 14, 14, 12, 3, 7, 9, 3, 1, 6, 5, 9, 7, 6, 2, 11, 10, 4, 11, 14, 10, 13, 11, 8, 11, 8, 1, 15, 5, 0, 10, 5, 6, 0, 5, 15, 11, 6, 6, 4, 10, 11, 8, 12, 0, 10, 11, 11, 11, 1, 13, 6},
|
||||
{7, 15, 0, 0, 11, 5, 7, 13, 3, 7, 3, 2, 5, 12, 6, 11, 14, 4, 9, 8, 9, 9, 13, 0, 15, 2, 13, 2, 15, 6, 15, 1, 1, 7, 4, 0, 10, 1, 8, 14, 0, 10, 12, 4, 5, 13, 9, 0, 7, 12, 13, 11, 11, 8, 8, 15, 2, 15, 4, 4, 9, 3, 10, 7},
|
||||
{0, 9, 3, 5, 14, 6, 7, 14, 7, 2, 13, 7, 3, 15, 9, 15, 2, 8, 0, 4, 6, 0, 15, 6, 2, 1, 14, 8, 5, 8, 2, 4, 2, 11, 9, 2, 15, 13, 11, 12, 8, 15, 3, 13, 2, 2, 10, 13, 1, 8, 7, 15, 13, 6, 7, 7, 4, 3, 14, 7, 0, 9, 15, 11},
|
||||
{8, 13, 7, 7, 8, 8, 7, 8, 1, 4, 10, 1, 12, 4, 14, 11, 7, 12, 15, 0, 10, 15, 9, 2, 14, 2, 14, 2, 4, 5, 13, 3, 2, 10, 0, 15, 7, 6, 8, 11, 7, 6, 10, 10, 4, 7, 10, 6, 6, 14, 10, 4, 14, 6, 12, 2, 8, 1, 9, 13, 3, 4, 3, 14},
|
||||
{10, 10, 6, 3, 8, 5, 10, 7, 11, 10, 9, 4, 8, 14, 9, 10, 0, 9, 8, 14, 11, 15, 8, 13, 13, 7, 13, 13, 13, 9, 12, 11, 6, 3, 9, 6, 0, 0, 6, 6, 11, 6, 4, 8, 1, 5, 1, 7, 9, 6, 13, 4, 3, 8, 8, 11, 9, 10, 6, 11, 12, 13, 14, 14},
|
||||
{14, 10, 0, 15, 14, 4, 3, 0, 12, 4, 0, 14, 11, 9, 0, 6, 4, 6, 0, 9, 8, 14, 4, 4, 6, 8, 2, 8, 10, 3, 8, 0, 1, 1, 15, 4, 2, 4, 13, 9, 9, 4, 0, 5, 5, 1, 2, 5, 11, 6, 2, 1, 7, 8, 10, 10, 1, 5, 8, 6, 7, 0, 4, 14},
|
||||
{0, 15, 10, 11, 13, 12, 7, 7, 4, 0, 9, 5, 2, 8, 0, 10, 6, 6, 7, 5, 6, 7, 9, 0, 1, 4, 8, 14, 10, 3, 5, 5, 11, 5, 1, 10, 6, 10, 0, 14, 1, 15, 11, 12, 8, 2, 7, 8, 4, 0, 3, 11, 9, 15, 3, 5, 15, 15, 14, 15, 3, 4, 5, 14},
|
||||
{5, 12, 12, 8, 0, 0, 14, 1, 4, 15, 3, 2, 2, 6, 1, 10, 7, 10, 14, 5, 14, 0, 8, 5, 9, 0, 12, 8, 9, 10, 3, 12, 3, 2, 0, 0, 12, 12, 7, 13, 2, 6, 4, 7, 10, 10, 14, 1, 11, 6, 10, 3, 12, 2, 1, 10, 7, 13, 10, 12, 14, 11, 14, 8},
|
||||
{9, 5, 3, 12, 4, 3, 10, 14, 7, 5, 11, 12, 2, 13, 9, 8, 5, 2, 6, 2, 4, 9, 10, 10, 4, 3, 4, 0, 11, 1, 10, 9, 4, 10, 4, 5, 8, 11, 1, 7, 13, 7, 6, 6, 3, 12, 0, 0, 15, 6, 12, 12, 13, 7, 14, 14, 11, 15, 7, 14, 12, 6, 15, 2},
|
||||
{15, 2, 0, 12, 15, 14, 8, 14, 7, 14, 0, 3, 3, 11, 12, 2, 3, 14, 13, 5, 12, 9, 6, 11, 7, 4, 5, 1, 7, 12, 0, 11, 1, 5, 6, 6, 8, 6, 12, 2, 12, 3, 10, 3, 4, 10, 3, 3, 3, 10, 10, 14, 3, 13, 15, 0, 7, 6, 15, 6, 13, 7, 4, 11},
|
||||
{11, 15, 5, 14, 0, 1, 1, 14, 2, 3, 15, 14, 4, 3, 11, 1, 6, 6, 0, 12, 3, 5, 15, 6, 3, 11, 13, 11, 7, 7, 8, 11, 5, 9, 10, 10, 9, 14, 7, 1, 7, 2, 8, 6, 6, 5, 1, 9, 6, 5, 8, 14, 2, 14, 2, 9, 3, 3, 4, 15, 13, 5, 2, 7},
|
||||
{7, 8, 13, 9, 15, 8, 11, 7, 1, 9, 15, 12, 6, 9, 3, 1, 10, 10, 11, 0, 0, 8, 14, 5, 11, 12, 14, 4, 3, 9, 12, 9, 14, 0, 0, 9, 12, 4, 1, 13, 3, 6, 3, 4, 13, 10, 2, 9, 3, 7, 7, 10, 7, 10, 10, 3, 5, 15, 8, 9, 11, 7, 1, 14},
|
||||
{5, 5, 9, 1, 15, 3, 3, 11, 6, 11, 13, 13, 4, 12, 7, 12, 4, 8, 14, 13, 7, 12, 13, 8, 10, 2, 1, 12, 11, 7, 0, 8, 10, 9, 15, 1, 3, 9, 10, 0, 9, 1, 14, 1, 1, 9, 2, 2, 8, 9, 5, 6, 3, 2, 15, 9, 15, 6, 3, 11, 14, 4, 0, 4},
|
||||
{9, 2, 10, 2, 0, 9, 6, 13, 13, 0, 13, 14, 3, 12, 1, 15, 9, 3, 12, 2, 5, 15, 6, 6, 15, 11, 7, 11, 0, 4, 0, 11, 10, 12, 7, 9, 3, 0, 2, 2, 13, 13, 9, 6, 9, 2, 6, 4, 3, 6, 5, 10, 10, 9, 7, 2, 4, 9, 13, 11, 2, 13, 6, 8},
|
||||
{13, 15, 9, 8, 6, 2, 3, 2, 2, 12, 5, 3, 8, 6, 11, 6, 15, 7, 10, 3, 15, 8, 7, 5, 3, 8, 4, 2, 11, 1, 0, 4, 1, 1, 6, 1, 13, 6, 5, 1, 2, 6, 7, 10, 4, 3, 10, 6, 2, 0, 7, 13, 15, 1, 13, 0, 12, 10, 15, 6, 2, 4, 14, 3},
|
||||
{5, 11, 14, 4, 0, 7, 12, 4, 4, 14, 12, 3, 4, 10, 7, 14, 6, 4, 14, 7, 0, 12, 5, 9, 15, 6, 15, 6, 3, 12, 0, 10, 11, 7, 1, 14, 13, 5, 1, 14, 5, 15, 12, 1, 9, 13, 9, 13, 14, 5, 10, 11, 12, 10, 15, 11, 9, 13, 2, 14, 9, 12, 2, 11},
|
||||
{2, 12, 5, 7, 1, 5, 2, 11, 8, 4, 15, 6, 9, 14, 5, 1, 15, 4, 3, 1, 11, 4, 2, 1, 4, 5, 4, 4, 7, 3, 3, 12, 4, 3, 2, 15, 13, 1, 14, 15, 1, 4, 6, 11, 13, 15, 6, 12, 12, 13, 6, 8, 10, 0, 10, 12, 1, 10, 3, 2, 9, 8, 2, 8},
|
||||
{10, 12, 12, 6, 8, 5, 4, 4, 5, 3, 6, 7, 15, 5, 10, 3, 8, 15, 14, 5, 6, 2, 14, 4, 1, 7, 1, 3, 12, 3, 12, 4, 10, 15, 6, 6, 0, 6, 6, 8, 6, 9, 5, 7, 5, 1, 9, 2, 4, 9, 0, 8, 1, 1, 14, 3, 7, 14, 8, 9, 0, 4, 11, 7},
|
||||
{13, 11, 14, 7, 0, 4, 0, 10, 12, 11, 10, 8, 6, 12, 13, 15, 9, 2, 14, 9, 3, 0, 12, 14, 11, 15, 4, 7, 15, 14, 4, 8, 15, 12, 9, 14, 7, 7, 9, 13, 14, 14, 4, 9, 13, 8, 1, 13, 6, 3, 12, 7, 0, 15, 6, 15, 7, 2, 3, 0, 9, 5, 13, 0},
|
||||
{3, 8, 12, 11, 5, 9, 9, 14, 8, 14, 14, 5, 9, 9, 12, 10, 3, 12, 13, 0, 0, 0, 6, 7, 12, 4, 2, 3, 8, 8, 9, 15, 11, 1, 12, 13, 10, 15, 11, 1, 2, 13, 10, 1, 7, 2, 7, 11, 8, 15, 7, 6, 4, 6, 5, 11, 11, 15, 2, 1, 11, 1, 1, 8},
|
||||
{10, 7, 7, 1, 4, 13, 9, 10, 2, 2, 3, 7, 12, 8, 5, 5, 5, 5, 3, 1, 5, 6, 8, 2, 8, 11, 5, 0, 4, 12, 12, 6, 7, 9, 14, 10, 11, 8, 0, 9, 11, 4, 14, 7, 7, 8, 2, 15, 12, 7, 4, 4, 13, 2, 0, 3, 14, 0, 1, 5, 2, 15, 7, 11},
|
||||
{3, 8, 10, 4, 1, 7, 3, 13, 5, 14, 0, 9, 3, 1, 0, 11, 2, 15, 4, 9, 6, 5, 14, 0, 2, 8, 1, 14, 7, 6, 1, 5, 5, 7, 2, 0, 5, 3, 4, 15, 13, 10, 9, 13, 13, 12, 5, 11, 11, 14, 13, 10, 8, 14, 0, 8, 1, 7, 2, 10, 12, 12, 1, 11},
|
||||
{11, 14, 4, 13, 3, 11, 10, 6, 15, 2, 5, 10, 14, 4, 13, 3, 12, 7, 12, 10, 4, 0, 0, 1, 14, 6, 1, 2, 2, 12, 9, 2, 3, 11, 1, 4, 10, 4, 4, 7, 7, 12, 4, 3, 12, 11, 9, 3, 15, 13, 6, 13, 7, 11, 5, 12, 5, 13, 15, 12, 0, 13, 12, 9},
|
||||
{8, 7, 2, 2, 5, 3, 10, 15, 10, 8, 1, 0, 4, 5, 7, 6, 15, 13, 2, 14, 6, 2, 9, 5, 9, 0, 5, 12, 8, 6, 4, 12, 6, 8, 14, 15, 7, 15, 11, 2, 2, 12, 7, 9, 7, 11, 15, 7, 0, 4, 5, 13, 7, 2, 5, 9, 0, 5, 7, 6, 7, 12, 4, 1},
|
||||
{11, 4, 2, 13, 6, 10, 9, 4, 12, 9, 9, 6, 4, 2, 14, 14, 9, 5, 5, 15, 15, 9, 8, 11, 4, 2, 8, 11, 14, 3, 8, 10, 14, 9, 6, 6, 4, 7, 11, 2, 3, 7, 5, 1, 14, 2, 9, 4, 0, 1, 10, 7, 6, 7, 1, 3, 13, 7, 3, 2, 12, 3, 6, 6},
|
||||
{11, 1, 14, 3, 14, 3, 9, 9, 0, 11, 14, 6, 14, 7, 14, 8, 4, 2, 5, 6, 13, 3, 4, 10, 8, 8, 10, 11, 5, 1, 15, 15, 7, 0, 4, 14, 15, 13, 14, 13, 3, 2, 1, 6, 0, 6, 6, 4, 15, 6, 0, 12, 5, 11, 1, 7, 3, 3, 13, 12, 12, 6, 3, 2},
|
||||
{7, 2, 10, 14, 14, 13, 4, 14, 10, 6, 0, 2, 7, 7, 2, 5, 14, 1, 5, 14, 15, 1, 2, 9, 2, 13, 1, 3, 6, 1, 3, 13, 10, 6, 11, 13, 1, 7, 13, 15, 2, 11, 9, 6, 13, 7, 9, 2, 3, 13, 10, 10, 6, 2, 5, 9, 1, 3, 0, 3, 1, 5, 3, 12},
|
||||
{11, 14, 4, 2, 10, 11, 15, 5, 9, 7, 8, 11, 10, 9, 5, 7, 14, 3, 12, 2, 7, 15, 12, 15, 4, 15, 12, 9, 2, 6, 6, 6, 8, 5, 0, 7, 14, 15, 14, 14, 3, 12, 7, 12, 2, 4, 1, 7, 1, 3, 4, 7, 1, 9, 11, 15, 15, 3, 7, 1, 10, 9, 14, 14},
|
||||
{4, 13, 11, 1, 9, 6, 5, 1, 11, 6, 6, 8, 3, 9, 8, 15, 13, 12, 3, 13, 5, 9, 10, 5, 12, 1, 15, 14, 12, 1, 10, 11, 5, 7, 3, 12, 9, 12, 0, 2, 2, 3, 14, 4, 2, 13, 1, 15, 11, 8, 3, 13, 0, 10, 5, 4, 6, 0, 14, 8, 1, 0, 6, 15},
|
||||
{15, 2, 0, 5, 2, 14, 9, 0, 10, 5, 12, 8, 5, 6, 0, 1, 9, 4, 4, 1, 4, 6, 14, 5, 3, 0, 2, 2, 14, 9, 7, 0, 2, 15, 12, 0, 10, 12, 9, 12, 15, 1, 9, 4, 15, 3, 0, 13, 0, 6, 5, 0, 2, 6, 11, 9, 13, 15, 6, 3, 5, 4, 0, 8},
|
||||
{4, 14, 8, 14, 13, 4, 4, 10, 6, 12, 15, 11, 7, 2, 15, 6, 9, 9, 1, 11, 13, 2, 7, 10, 4, 4, 5, 12, 14, 15, 8, 5, 6, 1, 11, 15, 4, 11, 5, 2, 5, 7, 3, 4, 5, 7, 3, 8, 10, 13, 7, 5, 6, 5, 10, 1, 12, 13, 3, 6, 2, 8, 7, 15},
|
||||
{3, 15, 4, 9, 14, 12, 6, 1, 7, 0, 7, 15, 10, 6, 5, 5, 15, 5, 9, 4, 7, 6, 14, 2, 1, 4, 10, 3, 12, 1, 7, 1, 0, 10, 2, 11, 14, 13, 7, 10, 5, 11, 5, 11, 15, 5, 0, 3, 15, 1, 2, 14, 13, 13, 10, 9, 15, 12, 10, 5, 2, 10, 0, 6},
|
||||
{4, 6, 5, 13, 11, 10, 15, 4, 2, 15, 13, 6, 7, 7, 4, 0, 4, 6, 7, 4, 9, 1, 6, 7, 6, 1, 4, 2, 0, 11, 6, 3, 14, 5, 9, 2, 2, 10, 1, 2, 13, 14, 4, 11, 4, 7, 12, 9, 8, 2, 2, 9, 5, 7, 9, 12, 8, 15, 0, 9, 12, 11, 1, 12},
|
||||
{11, 12, 11, 9, 8, 15, 4, 12, 13, 10, 6, 6, 6, 12, 3, 0, 6, 15, 15, 10, 6, 12, 5, 7, 10, 2, 7, 1, 6, 12, 9, 11, 11, 14, 1, 12, 15, 0, 6, 2, 12, 15, 4, 15, 14, 8, 3, 4, 15, 4, 13, 3, 14, 1, 3, 7, 6, 13, 9, 1, 0, 12, 4, 14},
|
||||
{12, 11, 13, 10, 10, 10, 3, 7, 12, 3, 13, 9, 6, 0, 12, 10, 4, 11, 5, 4, 11, 5, 7, 14, 6, 10, 12, 12, 13, 15, 12, 1, 13, 15, 15, 7, 1, 2, 8, 6, 1, 12, 12, 0, 4, 3, 3, 3, 7, 8, 9, 10, 7, 7, 0, 0, 11, 13, 15, 4, 9, 5, 10, 9},
|
||||
{6, 12, 3, 0, 9, 11, 6, 4, 9, 9, 1, 5, 9, 14, 3, 7, 15, 3, 5, 0, 5, 11, 7, 6, 13, 5, 10, 2, 12, 10, 2, 6, 0, 1, 1, 13, 9, 3, 11, 7, 8, 2, 10, 9, 13, 6, 6, 4, 12, 0, 3, 10, 9, 4, 15, 11, 14, 1, 9, 3, 0, 14, 6, 1},
|
||||
{11, 14, 10, 10, 11, 6, 4, 7, 10, 0, 7, 9, 3, 2, 13, 13, 9, 9, 2, 3, 3, 14, 10, 4, 14, 1, 10, 7, 14, 4, 9, 15, 3, 11, 5, 10, 7, 8, 3, 0, 1, 2, 2, 3, 12, 9, 6, 2, 11, 15, 3, 9, 3, 6, 8, 0, 4, 5, 7, 3, 0, 14, 7, 9},
|
||||
{4, 11, 13, 12, 6, 2, 3, 15, 15, 3, 5, 1, 0, 5, 10, 2, 5, 3, 7, 10, 15, 0, 5, 3, 2, 10, 12, 10, 8, 3, 9, 15, 5, 3, 7, 13, 5, 7, 13, 12, 5, 10, 2, 9, 10, 1, 9, 4, 14, 1, 10, 13, 1, 2, 2, 12, 5, 3, 14, 7, 7, 8, 13, 13},
|
||||
{10, 12, 11, 10, 0, 15, 4, 3, 0, 8, 3, 0, 15, 0, 3, 10, 10, 9, 15, 3, 13, 3, 8, 3, 8, 2, 14, 7, 1, 6, 13, 8, 2, 2, 12, 3, 3, 0, 10, 12, 0, 1, 1, 7, 5, 0, 13, 10, 7, 13, 9, 9, 13, 7, 0, 1, 0, 2, 14, 2, 13, 0, 8, 3},
|
||||
{11, 3, 11, 10, 12, 15, 11, 6, 14, 8, 8, 5, 7, 11, 3, 1, 13, 7, 13, 4, 15, 7, 2, 3, 8, 7, 3, 8, 9, 15, 10, 15, 9, 0, 5, 4, 1, 7, 13, 8, 2, 7, 1, 10, 1, 12, 12, 1, 7, 12, 13, 5, 14, 10, 9, 15, 12, 2, 10, 3, 10, 3, 9, 12},
|
||||
{9, 8, 11, 0, 5, 6, 1, 5, 9, 1, 0, 12, 12, 0, 12, 11, 2, 8, 4, 0, 1, 7, 7, 5, 1, 14, 1, 9, 13, 7, 2, 12, 8, 9, 12, 13, 1, 11, 5, 3, 12, 14, 15, 4, 9, 8, 12, 7, 11, 1, 3, 9, 11, 5, 7, 14, 4, 6, 12, 3, 4, 12, 7, 9},
|
||||
{10, 12, 2, 14, 14, 1, 11, 8, 3, 7, 13, 7, 2, 1, 14, 13, 7, 6, 15, 8, 15, 12, 13, 10, 11, 15, 4, 2, 6, 13, 12, 3, 2, 10, 15, 14, 10, 11, 8, 14, 9, 3, 12, 9, 15, 2, 14, 14, 5, 13, 7, 6, 2, 1, 1, 4, 1, 0, 13, 10, 1, 0, 2, 9},
|
||||
{10, 5, 11, 14, 12, 1, 12, 7, 12, 8, 10, 5, 6, 10, 0, 7, 5, 6, 11, 11, 13, 12, 0, 13, 0, 6, 11, 0, 14, 4, 2, 1, 12, 7, 1, 10, 7, 15, 5, 3, 14, 15, 1, 3, 1, 2, 10, 4, 11, 8, 2, 11, 2, 5, 5, 4, 15, 5, 10, 3, 1, 7, 2, 14},
|
||||
}
|
||||
mat := generateMatrix(hash)
|
||||
|
||||
if *mat != expectedMatrix {
|
||||
t.Fatal("The generated matrix doesn't match the test vector")
|
||||
}
|
||||
}
|
||||
|
||||
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},
|
||||
}
|
||||
@@ -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
|
||||
|
||||
37
domain/consensus/utils/pow/xoshiro.go
Normal file
37
domain/consensus/utils/pow/xoshiro.go
Normal 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
|
||||
}
|
||||
17
domain/consensus/utils/pow/xoshiro_test.go
Normal file
17
domain/consensus/utils/pow/xoshiro_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -45,7 +45,7 @@ func (p *p2pServer) MessageStream(stream protowire.P2P_MessageStreamServer) erro
|
||||
func (p *p2pServer) Connect(address string) (server.Connection, error) {
|
||||
log.Debugf("%s Dialing to %s", p.name, address)
|
||||
|
||||
const dialTimeout = 30 * time.Second
|
||||
const dialTimeout = 1 * time.Second
|
||||
ctx, cancel := context.WithTimeout(context.Background(), dialTimeout)
|
||||
defer cancel()
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
|
||||
const (
|
||||
appMajor uint = 0
|
||||
appMinor uint = 11
|
||||
appPatch uint = 0
|
||||
appPatch uint = 3
|
||||
)
|
||||
|
||||
// appBuild is defined as a variable so it can be overridden during the build
|
||||
|
||||
Reference in New Issue
Block a user