Verified Commit b261b489 authored by David Vorick's avatar David Vorick Committed by Luke Champine

prepare for ASIC hardfork

parent 69c7fe18
Pipeline #33081570 failed with stages
in 27 minutes and 58 seconds
...@@ -2,6 +2,7 @@ package consensus ...@@ -2,6 +2,7 @@ package consensus
import ( import (
"bytes" "bytes"
"encoding/binary"
"errors" "errors"
"fmt" "fmt"
"os" "os"
...@@ -107,6 +108,10 @@ func (cs *ConsensusSet) validateHeader(tx dbTx, h types.BlockHeader) error { ...@@ -107,6 +108,10 @@ func (cs *ConsensusSet) validateHeader(tx dbTx, h types.BlockHeader) error {
return err return err
} }
// Check that the nonce is a legal nonce.
if parent.Height >= types.ASICHardforkHeight && binary.LittleEndian.Uint64(h.Nonce[:])%types.ASICHardforkFactor != 0 {
return errors.New("block does not meet nonce requirements")
}
// Check that the target of the new block is sufficient. // Check that the target of the new block is sufficient.
if !checkHeaderTarget(h, parent.ChildTarget) { if !checkHeaderTarget(h, parent.ChildTarget) {
return modules.ErrBlockUnsolved return modules.ErrBlockUnsolved
...@@ -291,7 +296,6 @@ func (cs *ConsensusSet) managedAcceptBlocks(blocks []types.Block) (blockchainExt ...@@ -291,7 +296,6 @@ func (cs *ConsensusSet) managedAcceptBlocks(blocks []types.Block) (blockchainExt
} }
if setErr != nil { if setErr != nil {
if len(changes) == 0 { if len(changes) == 0 {
fmt.Println("Received an invalid block set.")
cs.log.Println("Consensus received an invalid block:", setErr) cs.log.Println("Consensus received an invalid block:", setErr)
} else { } else {
fmt.Println("Received a partially valid block set.") fmt.Println("Received a partially valid block set.")
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"errors" "errors"
"testing" "testing"
"time" "time"
"unsafe"
"gitlab.com/NebulousLabs/Sia/modules" "gitlab.com/NebulousLabs/Sia/modules"
"gitlab.com/NebulousLabs/Sia/persist" "gitlab.com/NebulousLabs/Sia/persist"
...@@ -645,8 +646,8 @@ func TestMissedTarget(t *testing.T) { ...@@ -645,8 +646,8 @@ func TestMissedTarget(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
for checkTarget(block, block.ID(), target) && block.Nonce[0] != 255 { for checkTarget(block, block.ID(), target) {
block.Nonce[0]++ *(*uint64)(unsafe.Pointer(&block.Nonce)) += types.ASICHardforkFactor
} }
if checkTarget(block, block.ID(), target) { if checkTarget(block, block.ID(), target) {
t.Fatal("unable to find a failing target") t.Fatal("unable to find a failing target")
......
...@@ -2,6 +2,7 @@ package consensus ...@@ -2,6 +2,7 @@ package consensus
import ( import (
"bytes" "bytes"
"encoding/binary"
"errors" "errors"
"gitlab.com/NebulousLabs/Sia/modules" "gitlab.com/NebulousLabs/Sia/modules"
...@@ -69,6 +70,10 @@ func (bv stdBlockValidator) ValidateBlock(b types.Block, id types.BlockID, minTi ...@@ -69,6 +70,10 @@ func (bv stdBlockValidator) ValidateBlock(b types.Block, id types.BlockID, minTi
return errEarlyTimestamp return errEarlyTimestamp
} }
// Check that the nonce is a legal nonce.
if height >= types.ASICHardforkHeight && binary.LittleEndian.Uint64(b.Nonce[:])%types.ASICHardforkFactor != 0 {
return errors.New("block does not meet nonce requirements")
}
// Check that the target of the new block is sufficient. // Check that the target of the new block is sufficient.
if !checkTarget(b, id, target) { if !checkTarget(b, id, target) {
return modules.ErrBlockUnsolved return modules.ErrBlockUnsolved
......
...@@ -3,6 +3,7 @@ package miner ...@@ -3,6 +3,7 @@ package miner
import ( import (
"bytes" "bytes"
"testing" "testing"
"unsafe"
"gitlab.com/NebulousLabs/Sia/crypto" "gitlab.com/NebulousLabs/Sia/crypto"
"gitlab.com/NebulousLabs/Sia/modules" "gitlab.com/NebulousLabs/Sia/modules"
...@@ -17,7 +18,7 @@ func solveHeader(header types.BlockHeader, target types.Target) types.BlockHeade ...@@ -17,7 +18,7 @@ func solveHeader(header types.BlockHeader, target types.Target) types.BlockHeade
for { for {
// Increment the nonce first to guarantee that a new header is formed // Increment the nonce first to guarantee that a new header is formed
// - this helps check for pointer errors. // - this helps check for pointer errors.
header.Nonce[0]++ *(*uint64)(unsafe.Pointer(&header.Nonce)) += types.ASICHardforkFactor
id := crypto.HashObject(header) id := crypto.HashObject(header)
if bytes.Compare(target[:], id[:]) >= 0 { if bytes.Compare(target[:], id[:]) >= 0 {
break break
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"time" "time"
"unsafe"
"gitlab.com/NebulousLabs/Sia/build" "gitlab.com/NebulousLabs/Sia/build"
"gitlab.com/NebulousLabs/Sia/crypto" "gitlab.com/NebulousLabs/Sia/crypto"
...@@ -173,10 +174,10 @@ func TestIntegrationBlocksMined(t *testing.T) { ...@@ -173,10 +174,10 @@ func TestIntegrationBlocksMined(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Unsolve the header - necessary because the target is very low when // Solve the header - necessary because the target is very low when
// mining. // mining.
for { for {
unsolvedHeader.Nonce[0]++ *(*uint64)(unsafe.Pointer(&unsolvedHeader.Nonce)) += types.ASICHardforkFactor
id := crypto.HashObject(unsolvedHeader) id := crypto.HashObject(unsolvedHeader)
if bytes.Compare(target[:], id[:]) < 0 { if bytes.Compare(target[:], id[:]) < 0 {
break break
......
...@@ -39,7 +39,7 @@ func solveBlock(b types.Block, target types.Target) (types.Block, bool) { ...@@ -39,7 +39,7 @@ func solveBlock(b types.Block, target types.Target) (types.Block, bool) {
return b, true return b, true
} }
*(*uint64)(unsafe.Pointer(&header[32])) = nonce *(*uint64)(unsafe.Pointer(&header[32])) = nonce
nonce++ nonce += types.ASICHardforkFactor
} }
return b, false return b, false
} }
......
...@@ -175,6 +175,13 @@ func TestValidRevertedTransaction(t *testing.T) { ...@@ -175,6 +175,13 @@ func TestValidRevertedTransaction(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer tpt.Close() defer tpt.Close()
// Mine a few extra blocks on tpt to get past the signature hardfork height.
for i := 0; i < 10; i++ {
_, err = tpt.miner.AddBlock()
if err != nil {
t.Fatal(err)
}
}
tpt2, err := blankTpoolTester(t.Name() + "-tpt2") tpt2, err := blankTpoolTester(t.Name() + "-tpt2")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
......
...@@ -16,6 +16,16 @@ func TestUpdate(t *testing.T) { ...@@ -16,6 +16,16 @@ func TestUpdate(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Mine a few more blocks to get past the hardfork height.
for i := types.BlockHeight(0); i <= 2; i++ {
b, _ := wt.miner.FindBlock()
err := wt.cs.AcceptBlock(b)
if err != nil {
t.Fatal(err)
}
}
// mine a block and add it to the consensus set // mine a block and add it to the consensus set
b, err := wt.miner.FindBlock() b, err := wt.miner.FindBlock()
if err != nil { if err != nil {
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"io/ioutil" "io/ioutil"
"testing" "testing"
"time" "time"
"unsafe"
"gitlab.com/NebulousLabs/Sia/crypto" "gitlab.com/NebulousLabs/Sia/crypto"
"gitlab.com/NebulousLabs/Sia/types" "gitlab.com/NebulousLabs/Sia/types"
...@@ -134,7 +135,7 @@ func TestMinerHeader(t *testing.T) { ...@@ -134,7 +135,7 @@ func TestMinerHeader(t *testing.T) {
copy(header[:], targetAndHeader[32:]) copy(header[:], targetAndHeader[32:])
headerHash := crypto.HashObject(header) headerHash := crypto.HashObject(header)
for headerHash[0] >= types.RootTarget[0] { for headerHash[0] >= types.RootTarget[0] {
header[35]++ *(*uint64)(unsafe.Pointer(&header[32])) += types.ASICHardforkFactor
headerHash = crypto.HashObject(header) headerHash = crypto.HashObject(header)
} }
......
...@@ -40,7 +40,7 @@ func solveHeader(target types.Target, bh types.BlockHeader) (types.BlockHeader, ...@@ -40,7 +40,7 @@ func solveHeader(target types.Target, bh types.BlockHeader) (types.BlockHeader,
return bh, nil return bh, nil
} }
*(*uint64)(unsafe.Pointer(&header[32])) = nonce *(*uint64)(unsafe.Pointer(&header[32])) = nonce
nonce++ nonce += types.ASICHardforkFactor
} }
return bh, errors.New("couldn't solve block") return bh, errors.New("couldn't solve block")
} }
...@@ -15,6 +15,19 @@ import ( ...@@ -15,6 +15,19 @@ import (
) )
var ( var (
// ASICHardforkHeight is the height at which the hardfork targeting
// selected ASICs was activated.
ASICHardforkHeight BlockHeight
// ASICHardforkFactor is the factor by which the hashrate of targeted
// ASICs will be reduced.
ASICHardforkFactor = uint64(1)
// ASICHardforkReplayProtectionPrefix is a byte that prefixes
// SiacoinInputs and SiafundInputs when calculating SigHashes to protect
// against replay attacks.
ASICHardforkReplayProtectionPrefix = []byte(nil)
// BlockFrequency is the desired number of seconds that // BlockFrequency is the desired number of seconds that
// should elapse, on average, between successive Blocks. // should elapse, on average, between successive Blocks.
BlockFrequency BlockHeight BlockFrequency BlockHeight
...@@ -149,6 +162,8 @@ func init() { ...@@ -149,6 +162,8 @@ func init() {
// can coordinate their actions over a the developer testnets, but fast // can coordinate their actions over a the developer testnets, but fast
// enough that there isn't much time wasted on waiting for things to // enough that there isn't much time wasted on waiting for things to
// happen. // happen.
ASICHardforkHeight = 20
BlockFrequency = 12 // 12 seconds: slow enough for developers to see ~each block, fast enough that blocks don't waste time. BlockFrequency = 12 // 12 seconds: slow enough for developers to see ~each block, fast enough that blocks don't waste time.
MaturityDelay = 10 // 60 seconds before a delayed output matures. MaturityDelay = 10 // 60 seconds before a delayed output matures.
GenesisTimestamp = Timestamp(1424139000) // Change as necessary. GenesisTimestamp = Timestamp(1424139000) // Change as necessary.
...@@ -187,6 +202,8 @@ func init() { ...@@ -187,6 +202,8 @@ func init() {
} else if build.Release == "testing" { } else if build.Release == "testing" {
// 'testing' settings are for automatic testing, and create much faster // 'testing' settings are for automatic testing, and create much faster
// environments than a human can interact with. // environments than a human can interact with.
ASICHardforkHeight = 5
BlockFrequency = 1 // As fast as possible BlockFrequency = 1 // As fast as possible
MaturityDelay = 3 MaturityDelay = 3
GenesisTimestamp = CurrentTimestamp() - 1e6 GenesisTimestamp = CurrentTimestamp() - 1e6
...@@ -231,6 +248,7 @@ func init() { ...@@ -231,6 +248,7 @@ func init() {
} else if build.Release == "standard" { } else if build.Release == "standard" {
// 'standard' settings are for the full network. They are slow enough // 'standard' settings are for the full network. They are slow enough
// that the network is secure in a real-world byzantine environment. // that the network is secure in a real-world byzantine environment.
ASICHardforkHeight = 179000
// A block time of 1 block per 10 minutes is chosen to follow Bitcoin's // A block time of 1 block per 10 minutes is chosen to follow Bitcoin's
// example. The security lost by lowering the block time is not // example. The security lost by lowering the block time is not
......
...@@ -196,6 +196,9 @@ func (t *Transaction) wholeSigHash(sig TransactionSignature, height BlockHeight) ...@@ -196,6 +196,9 @@ func (t *Transaction) wholeSigHash(sig TransactionSignature, height BlockHeight)
e.WriteInt(len((t.SiacoinInputs))) e.WriteInt(len((t.SiacoinInputs)))
for i := range t.SiacoinInputs { for i := range t.SiacoinInputs {
if height >= ASICHardforkHeight {
e.Write(ASICHardforkReplayProtectionPrefix)
}
t.SiacoinInputs[i].MarshalSia(e) t.SiacoinInputs[i].MarshalSia(e)
} }
e.WriteInt(len((t.SiacoinOutputs))) e.WriteInt(len((t.SiacoinOutputs)))
...@@ -216,6 +219,9 @@ func (t *Transaction) wholeSigHash(sig TransactionSignature, height BlockHeight) ...@@ -216,6 +219,9 @@ func (t *Transaction) wholeSigHash(sig TransactionSignature, height BlockHeight)
} }
e.WriteInt(len((t.SiafundInputs))) e.WriteInt(len((t.SiafundInputs)))
for i := range t.SiafundInputs { for i := range t.SiafundInputs {
if height >= ASICHardforkHeight {
e.Write(ASICHardforkReplayProtectionPrefix)
}
t.SiafundInputs[i].MarshalSia(e) t.SiafundInputs[i].MarshalSia(e)
} }
e.WriteInt(len((t.SiafundOutputs))) e.WriteInt(len((t.SiafundOutputs)))
...@@ -249,6 +255,9 @@ func (t *Transaction) partialSigHash(cf CoveredFields, height BlockHeight) (hash ...@@ -249,6 +255,9 @@ func (t *Transaction) partialSigHash(cf CoveredFields, height BlockHeight) (hash
h := crypto.NewHash() h := crypto.NewHash()
for _, input := range cf.SiacoinInputs { for _, input := range cf.SiacoinInputs {
if height >= ASICHardforkHeight {
h.Write(ASICHardforkReplayProtectionPrefix)
}
t.SiacoinInputs[input].MarshalSia(h) t.SiacoinInputs[input].MarshalSia(h)
} }
for _, output := range cf.SiacoinOutputs { for _, output := range cf.SiacoinOutputs {
...@@ -264,6 +273,9 @@ func (t *Transaction) partialSigHash(cf CoveredFields, height BlockHeight) (hash ...@@ -264,6 +273,9 @@ func (t *Transaction) partialSigHash(cf CoveredFields, height BlockHeight) (hash
t.StorageProofs[storageProof].MarshalSia(h) t.StorageProofs[storageProof].MarshalSia(h)
} }
for _, siafundInput := range cf.SiafundInputs { for _, siafundInput := range cf.SiafundInputs {
if height >= ASICHardforkHeight {
h.Write(ASICHardforkReplayProtectionPrefix)
}
t.SiafundInputs[siafundInput].MarshalSia(h) t.SiafundInputs[siafundInput].MarshalSia(h)
} }
for _, siafundOutput := range cf.SiafundOutputs { for _, siafundOutput := range cf.SiafundOutputs {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment