github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/types/block.go (about)

     1  package types
     2  
     3  // block.go defines the Block type for Sia, and provides some helper functions
     4  // for working with blocks.
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/hex"
     9  	"hash"
    10  	"unsafe"
    11  
    12  	"SiaPrime/build"
    13  	"SiaPrime/crypto"
    14  )
    15  
    16  const (
    17  	// BlockHeaderSize is the size, in bytes, of a block header.
    18  	// 32 (ParentID) + 8 (Nonce) + 8 (Timestamp) + 32 (MerkleRoot)
    19  	BlockHeaderSize = 80
    20  )
    21  
    22  type (
    23  	// A Block is a summary of changes to the state that have occurred since the
    24  	// previous block. Blocks reference the ID of the previous block (their
    25  	// "parent"), creating the linked-list commonly known as the blockchain. Their
    26  	// primary function is to bundle together transactions on the network. Blocks
    27  	// are created by "miners," who collect transactions from other nodes, and
    28  	// then try to pick a Nonce that results in a block whose BlockID is below a
    29  	// given Target.
    30  	Block struct {
    31  		ParentID     BlockID         `json:"parentid"`
    32  		Nonce        BlockNonce      `json:"nonce"`
    33  		Timestamp    Timestamp       `json:"timestamp"`
    34  		MinerPayouts []SiacoinOutput `json:"minerpayouts"`
    35  		Transactions []Transaction   `json:"transactions"`
    36  	}
    37  
    38  	// A BlockHeader contains the data that, when hashed, produces the Block's ID.
    39  	BlockHeader struct {
    40  		ParentID   BlockID     `json:"parentid"`
    41  		Nonce      BlockNonce  `json:"nonce"`
    42  		Timestamp  Timestamp   `json:"timestamp"`
    43  		MerkleRoot crypto.Hash `json:"merkleroot"`
    44  	}
    45  
    46  	// BlockHeight is the number of blocks that exist after the genesis block.
    47  	BlockHeight uint64
    48  	// A BlockID is the hash of a BlockHeader. A BlockID uniquely
    49  	// identifies a Block, and indicates the amount of work performed
    50  	// to mine that Block. The more leading zeros in the BlockID, the
    51  	// more work was performed.
    52  	BlockID crypto.Hash
    53  	// The BlockNonce is a "scratch space" that miners can freely alter to produce
    54  	// a BlockID that satisfies a given Target.
    55  	BlockNonce [8]byte
    56  )
    57  
    58  // CalculateDevSubsidy takes a block and a height and determines the block
    59  // subsidies for the dev fund.
    60  func CalculateDevSubsidy(height BlockHeight) Currency {
    61  	coinbase := CalculateCoinbase(height)
    62  
    63  	devSubsidy := NewCurrency64(0)
    64  	if DevFundEnabled && (height >= DevFundInitialBlockHeight) {
    65  		devFundDecayPercentage := uint64(100)
    66  		if height >= DevFundDecayEndBlockHeight {
    67  			devFundDecayPercentage = uint64(0)
    68  		} else if height >= DevFundDecayStartBlockHeight {
    69  			devFundDecayStartBlockHeight := uint64(DevFundDecayStartBlockHeight)
    70  			devFundDecayEndBlockHeight := uint64(DevFundDecayEndBlockHeight)
    71  			devFundDecayPercentage = uint64(100) - (uint64(height)-devFundDecayStartBlockHeight)*uint64(100)/(devFundDecayEndBlockHeight-devFundDecayStartBlockHeight)
    72  		}
    73  
    74  		devFundPercentageRange := DevFundInitialPercentage - DevFundFinalPercentage
    75  		devFundPercentage := DevFundFinalPercentage*uint64(100) + devFundPercentageRange*devFundDecayPercentage
    76  
    77  		devSubsidy = coinbase.Mul(NewCurrency64(devFundPercentage)).Div(NewCurrency64(10000))
    78  	}
    79  
    80  	return devSubsidy
    81  }
    82  
    83  // CalculateCoinbase calculates the coinbase for a given height. The coinbase
    84  // equation is:
    85  //
    86  //     coinbase := max(InitialCoinbase - height, MinimumCoinbase) * SiacoinPrecision
    87  func CalculateCoinbase(height BlockHeight) Currency {
    88  	base := InitialCoinbase - uint64(height)
    89  	if uint64(height) > InitialCoinbase || base < MinimumCoinbase {
    90  		base = MinimumCoinbase
    91  	}
    92  	return NewCurrency64(base).Mul(SiacoinPrecision)
    93  }
    94  
    95  // CalculateNumSiacoins calculates the number of siacoins in circulation at a
    96  // given height.
    97  func CalculateNumSiacoins(height BlockHeight) Currency {
    98  	airdropCoins := AirdropCommunityValue.Add(AirdropPoolValue).Add(AirdropNebulousLabsValue).Add(AirdropSiaPrimeValue)
    99  
   100  	deflationBlocks := BlockHeight(InitialCoinbase - MinimumCoinbase)
   101  	avgDeflationSiacoins := CalculateCoinbase(0).Add(CalculateCoinbase(height)).Div(NewCurrency64(2))
   102  	if height <= deflationBlocks {
   103  		deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(height + 1)))
   104  		return airdropCoins.Add(deflationSiacoins)
   105  	}
   106  	deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(deflationBlocks + 1)))
   107  	trailingSiacoins := NewCurrency64(uint64(height - deflationBlocks)).Mul(CalculateCoinbase(height))
   108  	return airdropCoins.Add(deflationSiacoins.Add(trailingSiacoins))
   109  }
   110  
   111  // ID returns the ID of a Block, which is calculated by hashing the header.
   112  func (h BlockHeader) ID() BlockID {
   113  	return BlockID(crypto.HashObject(h))
   114  }
   115  
   116  // CalculateMinerFees calculates the sum of a block's miner transaction fees
   117  func (b Block) CalculateMinerFees() Currency {
   118  	fees := NewCurrency64(0)
   119  	for _, txn := range b.Transactions {
   120  		for _, fee := range txn.MinerFees {
   121  			fees = fees.Add(fee)
   122  		}
   123  	}
   124  	return fees
   125  }
   126  
   127  // CalculateSubsidy takes a block and a height and determines the block
   128  // subsidy.
   129  func (b Block) CalculateSubsidy(height BlockHeight) Currency {
   130  	subsidy := CalculateCoinbase(height)
   131  	for _, txn := range b.Transactions {
   132  		for _, fee := range txn.MinerFees {
   133  			subsidy = subsidy.Add(fee)
   134  		}
   135  	}
   136  	return subsidy
   137  }
   138  
   139  // CalculateSubsidies takes a block and a height and determines the block
   140  // subsidies for miners and the dev fund.
   141  func (b Block) CalculateSubsidies(height BlockHeight) (Currency, Currency) {
   142  	coinbase := CalculateCoinbase(height)
   143  
   144  	devSubsidy := NewCurrency64(0)
   145  	if DevFundEnabled && (height >= DevFundInitialBlockHeight) {
   146  		devFundDecayPercentage := uint64(100)
   147  		if height >= DevFundDecayEndBlockHeight {
   148  			devFundDecayPercentage = uint64(0)
   149  		} else if height >= DevFundDecayStartBlockHeight {
   150  			devFundDecayStartBlockHeight := uint64(DevFundDecayStartBlockHeight)
   151  			devFundDecayEndBlockHeight := uint64(DevFundDecayEndBlockHeight)
   152  			devFundDecayPercentage = uint64(100) - (uint64(height)-devFundDecayStartBlockHeight)*uint64(100)/(devFundDecayEndBlockHeight-devFundDecayStartBlockHeight)
   153  		}
   154  
   155  		devFundPercentageRange := DevFundInitialPercentage - DevFundFinalPercentage
   156  		devFundPercentage := DevFundFinalPercentage*uint64(100) + devFundPercentageRange*devFundDecayPercentage
   157  
   158  		devSubsidy = coinbase.Mul(NewCurrency64(devFundPercentage)).Div(NewCurrency64(10000))
   159  	}
   160  
   161  	minerSubsidy := coinbase.Sub(devSubsidy).Add(b.CalculateMinerFees())
   162  	return minerSubsidy, devSubsidy
   163  }
   164  
   165  // Header returns the header of a block.
   166  func (b Block) Header() BlockHeader {
   167  	return BlockHeader{
   168  		ParentID:   b.ParentID,
   169  		Nonce:      b.Nonce,
   170  		Timestamp:  b.Timestamp,
   171  		MerkleRoot: b.MerkleRoot(),
   172  	}
   173  }
   174  
   175  // ID returns the ID of a Block, which is calculated by hashing the
   176  // concatenation of the block's parent's ID, nonce, and the result of the
   177  // b.MerkleRoot(). It is equivalent to calling block.Header().ID()
   178  func (b Block) ID() BlockID {
   179  	return b.Header().ID()
   180  }
   181  
   182  // MerkleTree return the MerkleTree of the block
   183  func (b Block) MerkleTree() *crypto.MerkleTree {
   184  	tree := crypto.NewTree()
   185  	var buf bytes.Buffer
   186  	e := encoder(&buf)
   187  	for _, payout := range b.MinerPayouts {
   188  		payout.MarshalSia(e)
   189  		tree.Push(buf.Bytes())
   190  		buf.Reset()
   191  	}
   192  	for _, txn := range b.Transactions {
   193  		txn.MarshalSia(e)
   194  		tree.Push(buf.Bytes())
   195  		buf.Reset()
   196  	}
   197  
   198  	// Sanity check - verify that this root is the same as the root provided in
   199  	// the old implementation.
   200  	if build.DEBUG {
   201  		verifyTree := crypto.NewTree()
   202  		for _, payout := range b.MinerPayouts {
   203  			verifyTree.PushObject(payout)
   204  		}
   205  		for _, txn := range b.Transactions {
   206  			verifyTree.PushObject(txn)
   207  		}
   208  		if tree.Root() != verifyTree.Root() {
   209  			panic("Block MerkleRoot implementation is broken")
   210  		}
   211  	}
   212  	return tree
   213  }
   214  
   215  // MerkleRoot calculates the Merkle root of a Block. The leaves of the Merkle
   216  // tree are composed of the miner outputs (one leaf per payout), and the
   217  // transactions (one leaf per transaction).
   218  func (b Block) MerkleRoot() crypto.Hash {
   219  	return b.MerkleTree().Root()
   220  }
   221  
   222  // MinerPayoutID returns the ID of the miner payout at the given index, which
   223  // is calculated by hashing the concatenation of the BlockID and the payout
   224  // index.
   225  func (b Block) MinerPayoutID(i uint64) SiacoinOutputID {
   226  	return SiacoinOutputID(crypto.HashAll(
   227  		b.ID(),
   228  		i,
   229  	))
   230  }
   231  
   232  // MerkleBranches returns the merkle branches of a block, as used in stratum
   233  // mining.
   234  func (b Block) MerkleBranches() []string {
   235  	mbranch := crypto.NewTree()
   236  	var buf bytes.Buffer
   237  	for _, payout := range b.MinerPayouts {
   238  		payout.MarshalSia(&buf)
   239  		mbranch.Push(buf.Bytes())
   240  		buf.Reset()
   241  	}
   242  
   243  	for _, txn := range b.Transactions {
   244  		txn.MarshalSia(&buf)
   245  		mbranch.Push(buf.Bytes())
   246  		buf.Reset()
   247  	}
   248  	//
   249  	// This whole approach needs to be revisited.  I basically am cheating to look
   250  	// inside the merkle tree struct to determine if the head is a leaf or not
   251  	//
   252  	type SubTree struct {
   253  		next   *SubTree
   254  		height int // Int is okay because a height over 300 is physically unachievable.
   255  		sum    []byte
   256  	}
   257  
   258  	type Tree struct {
   259  		head         *SubTree
   260  		hash         hash.Hash
   261  		currentIndex uint64
   262  		proofIndex   uint64
   263  		proofSet     [][]byte
   264  		cachedTree   bool
   265  	}
   266  	tr := *(*Tree)(unsafe.Pointer(mbranch))
   267  
   268  	var merkle []string
   269  	//	h.log.Debugf("mBranch Hash %s\n", mbranch.Root().String())
   270  	for st := tr.head; st != nil; st = st.next {
   271  		//		h.log.Debugf("Height %d Hash %x\n", st.height, st.sum)
   272  		merkle = append(merkle, hex.EncodeToString(st.sum))
   273  	}
   274  	return merkle
   275  }