Commit 21a37df0 authored by David Vorick's avatar David Vorick

add test to count total number of coins and funds

parent 28baa309
......@@ -20,7 +20,8 @@ Cryptographic Algorithms
Sia uses cryptographic hashing and cryptographic signing, each of which has
many potentially secure algorithms that can be used. We acknoledge our
inexperience, and acknoledge that if we have picked the optimal algorithms for
each, it will have been by accident.
each, it will have been by accident. In particular, there is low confidence
that ed25519 is the correct choice for a signature algorithm.
For hashing, our primary goal is to use an algorithm that cannot be merge mined
with Bitcoin, even partially. A secondary goal is hashing speed.
......@@ -371,3 +372,7 @@ The required target for the next block shall be [0, 0, 0, 1, 0...], where each
value is a byte.
The genesis block does not need to meet a particular target.
The genesis state needs to have an output to the zero address from the genesis
block, and a siafund output to the Nebulous Genesis Address for 10,000
siafunds (both the spend hash and the claim destination), having the zero id.
......@@ -14,6 +14,7 @@ const (
TargetWindow = BlockHeight(80) // Number of blocks to use when calculating the target.
MedianTimestampWindow = 11 // Number of blocks that get considered when determining if a timestamp is valid. Should be an odd number.
FutureThreshold = Timestamp(3 * 60 * 60) // Seconds into the future block timestamps are valid.
SiafundCount = Currency(10 * 1000) // The total (static) number of siafunds.
InitialCoinbase = Currency(300 * 1000)
MinimumCoinbase = Currency(30 * 1000)
......
......@@ -14,6 +14,7 @@ const (
TargetWindow = BlockHeight(2000) // Number of blocks to use when calculating the target.
MedianTimestampWindow = 11 // Number of blocks that get considered when determining if a timestamp is valid - should be an odd number.
FutureThreshold = Timestamp(3 * 60 * 60) // Seconds into the future block timestamps are valid.
SiafundCount = Currency(10 * 1000) // The total (static) number of siafunds.
InitialCoinbase = Currency(300 * 1000)
MinimumCoinbase = Currency(30 * 1000)
......
......@@ -14,6 +14,7 @@ const (
TargetWindow = BlockHeight(1000) // Number of blocks to use when calculating the target.
MedianTimestampWindow = 11 // Number of blocks that get considered when determining if a timestamp is valid - should be an odd number.
FutureThreshold = Timestamp(3 * 60 * 60) // Seconds into the future block timestamps are valid.
SiafundCount = Currency(10 * 1000) // The total (static) number of siafunds.
InitialCoinbase = Currency(300 * 1000)
MinimumCoinbase = Currency(30 * 1000)
......
......@@ -48,12 +48,44 @@ func rewindApplyCheck(t *testing.T, s *State) {
}
}
// currencyCheck uses the height to determine the total amount of currency that
// should be in the system, and then tallys up the outputs to see if that is
// the case.
func currencyCheck(t *testing.T, s *State) {
siafunds := Currency(0)
for _, siafundOutput := range s.unspentSiafundOutputs {
siafunds += siafundOutput.Value
}
if siafunds != SiafundCount {
t.Error("siafunds inconsistency")
}
expectedSiacoins := Currency(0)
for i := BlockHeight(0); i <= s.Height(); i++ {
expectedSiacoins += CalculateCoinbase(i)
}
siacoins := Currency(0)
for _, output := range s.unspentOutputs {
siacoins += output.Value
}
for _, contract := range s.openContracts {
siacoins += contract.Payout
}
siacoins += s.siafundPool
if siacoins != expectedSiacoins {
t.Error(siacoins)
t.Error(expectedSiacoins)
t.Error("siacoins inconsistency")
}
}
// consistencyChecks calls all of the consistency functions on each of the
// states.
func consistencyChecks(t *testing.T, states ...*State) {
for _, s := range states {
currentPathCheck(t, s)
rewindApplyCheck(t, s)
currencyCheck(t, s)
}
}
......
......@@ -33,10 +33,12 @@ type State struct {
// Consensus Variables - the current state of consensus according to the
// longest fork.
currentBlockID BlockID
currentPath map[BlockHeight]BlockID
unspentOutputs map[OutputID]Output
openContracts map[ContractID]FileContract
currentBlockID BlockID
currentPath map[BlockHeight]BlockID
siafundPool Currency
unspentSiafundOutputs map[OutputID]SiafundOutput
unspentOutputs map[OutputID]Output
openContracts map[ContractID]FileContract
mu sync.RWMutex
}
......@@ -47,11 +49,12 @@ type State struct {
func CreateGenesisState(genesisTime Timestamp) (s *State) {
// Create a new state and initialize the maps.
s = &State{
badBlocks: make(map[BlockID]struct{}),
blockMap: make(map[BlockID]*blockNode),
currentPath: make(map[BlockHeight]BlockID),
openContracts: make(map[ContractID]FileContract),
unspentOutputs: make(map[OutputID]Output),
badBlocks: make(map[BlockID]struct{}),
blockMap: make(map[BlockID]*blockNode),
currentPath: make(map[BlockHeight]BlockID),
openContracts: make(map[ContractID]FileContract),
unspentOutputs: make(map[OutputID]Output),
unspentSiafundOutputs: make(map[OutputID]SiafundOutput),
}
// Create the genesis block and add it as the BlockRoot.
......@@ -68,6 +71,15 @@ func CreateGenesisState(genesisTime Timestamp) (s *State) {
// Fill out the consensus informaiton for the genesis block.
s.currentBlockID = genesisBlock.ID()
s.currentPath[BlockHeight(0)] = genesisBlock.ID()
s.unspentOutputs[genesisBlock.MinerPayoutID(0)] = Output{
Value: CalculateCoinbase(0),
SpendHash: ZeroAddress,
}
s.unspentSiafundOutputs[OutputID{}] = SiafundOutput{
Value: 10 * 1000,
SpendHash: ZeroAddress, // TODO: change to Nebulous Genesis Address
ClaimDestination: ZeroAddress, // TODO: change to Nebulous Genesis Address
}
return
}
......
......@@ -20,6 +20,26 @@ type InputSignatures struct {
Index int
}
// validStorageProofs checks that a transaction follows the limitations placed
// on transactions with storage proofs.
func (t Transaction) validStorageProofs() bool {
if len(t.StorageProofs) == 0 {
return true
}
if len(t.Outputs) != 0 {
return false
}
if len(t.FileContracts) != 0 {
return false
}
if len(t.SiafundOutputs) != 0 {
return false
}
return true
}
// validCoveredFields makes sure that all covered fields objects in the
// signatures follow the rules. This means that if `WholeTransaction` is set to
// true, all fields except for `Signatures` must be empty. All fields must be
......@@ -207,6 +227,12 @@ func (s *State) validInput(input Input) (err error) {
// ValidTransaction returns err = nil if the transaction is valid, otherwise
// returns an error explaining what wasn't valid.
func (s *State) validTransaction(t Transaction) (err error) {
// Check that the storage proof guidelines are followed.
if !t.validStorageProofs() {
err = errors.New("transaction contains storage proofs and conflicts")
return
}
// Validate each input and get the total amount of Currency.
inputSum := Currency(0)
for _, input := range t.Inputs {
......
......@@ -6,8 +6,6 @@ package consensus
// TODO: Enforce the 100 block spending hold on certain types of outputs: Miner
// payouts, storage proof outputs, siafund claims.
// TODO: Enforce restrictions on which storage proof transactions are legal
// TODO: Enforce siafund rules in consensus.
import (
......@@ -120,7 +118,7 @@ type SiafundInput struct {
// output is spent. The ClaimStart will be comapred to the SiafundPool to
// figure out how many siacoins the ClaimDestination will receive.
type SiafundOutput struct {
Value Siafund
Value Currency
SpendHash CoinAddress
ClaimDestination CoinAddress
ClaimStart Currency
......
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