github.com/nebulouslabs/sia@v1.3.7/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  
     9  	"github.com/NebulousLabs/Sia/build"
    10  	"github.com/NebulousLabs/Sia/crypto"
    11  	"github.com/NebulousLabs/Sia/encoding"
    12  )
    13  
    14  const (
    15  	// BlockHeaderSize is the size, in bytes, of a block header.
    16  	// 32 (ParentID) + 8 (Nonce) + 8 (Timestamp) + 32 (MerkleRoot)
    17  	BlockHeaderSize = 80
    18  )
    19  
    20  type (
    21  	// A Block is a summary of changes to the state that have occurred since the
    22  	// previous block. Blocks reference the ID of the previous block (their
    23  	// "parent"), creating the linked-list commonly known as the blockchain. Their
    24  	// primary function is to bundle together transactions on the network. Blocks
    25  	// are created by "miners," who collect transactions from other nodes, and
    26  	// then try to pick a Nonce that results in a block whose BlockID is below a
    27  	// given Target.
    28  	Block struct {
    29  		ParentID     BlockID         `json:"parentid"`
    30  		Nonce        BlockNonce      `json:"nonce"`
    31  		Timestamp    Timestamp       `json:"timestamp"`
    32  		MinerPayouts []SiacoinOutput `json:"minerpayouts"`
    33  		Transactions []Transaction   `json:"transactions"`
    34  	}
    35  
    36  	// A BlockHeader contains the data that, when hashed, produces the Block's ID.
    37  	BlockHeader struct {
    38  		ParentID   BlockID     `json:"parentid"`
    39  		Nonce      BlockNonce  `json:"nonce"`
    40  		Timestamp  Timestamp   `json:"timestamp"`
    41  		MerkleRoot crypto.Hash `json:"merkleroot"`
    42  	}
    43  
    44  	// BlockHeight is the number of blocks that exist after the genesis block.
    45  	BlockHeight uint64
    46  	// A BlockID is the hash of a BlockHeader. A BlockID uniquely
    47  	// identifies a Block, and indicates the amount of work performed
    48  	// to mine that Block. The more leading zeros in the BlockID, the
    49  	// more work was performed.
    50  	BlockID crypto.Hash
    51  	// The BlockNonce is a "scratch space" that miners can freely alter to produce
    52  	// a BlockID that satisfies a given Target.
    53  	BlockNonce [8]byte
    54  )
    55  
    56  // CalculateCoinbase calculates the coinbase for a given height. The coinbase
    57  // equation is:
    58  //
    59  //     coinbase := max(InitialCoinbase - height, MinimumCoinbase) * SiacoinPrecision
    60  func CalculateCoinbase(height BlockHeight) Currency {
    61  	base := InitialCoinbase - uint64(height)
    62  	if uint64(height) > InitialCoinbase || base < MinimumCoinbase {
    63  		base = MinimumCoinbase
    64  	}
    65  	return NewCurrency64(base).Mul(SiacoinPrecision)
    66  }
    67  
    68  // CalculateNumSiacoins calculates the number of siacoins in circulation at a
    69  // given height.
    70  func CalculateNumSiacoins(height BlockHeight) Currency {
    71  	deflationBlocks := BlockHeight(InitialCoinbase - MinimumCoinbase)
    72  	avgDeflationSiacoins := CalculateCoinbase(0).Add(CalculateCoinbase(height)).Div(NewCurrency64(2))
    73  	if height <= deflationBlocks {
    74  		deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(height + 1)))
    75  		return deflationSiacoins
    76  	}
    77  	deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(deflationBlocks + 1)))
    78  	trailingSiacoins := NewCurrency64(uint64(height - deflationBlocks)).Mul(CalculateCoinbase(height))
    79  	return deflationSiacoins.Add(trailingSiacoins)
    80  }
    81  
    82  // ID returns the ID of a Block, which is calculated by hashing the header.
    83  func (h BlockHeader) ID() BlockID {
    84  	return BlockID(crypto.HashObject(h))
    85  }
    86  
    87  // CalculateSubsidy takes a block and a height and determines the block
    88  // subsidy.
    89  func (b Block) CalculateSubsidy(height BlockHeight) Currency {
    90  	subsidy := CalculateCoinbase(height)
    91  	for _, txn := range b.Transactions {
    92  		for _, fee := range txn.MinerFees {
    93  			subsidy = subsidy.Add(fee)
    94  		}
    95  	}
    96  	return subsidy
    97  }
    98  
    99  // Header returns the header of a block.
   100  func (b Block) Header() BlockHeader {
   101  	return BlockHeader{
   102  		ParentID:   b.ParentID,
   103  		Nonce:      b.Nonce,
   104  		Timestamp:  b.Timestamp,
   105  		MerkleRoot: b.MerkleRoot(),
   106  	}
   107  }
   108  
   109  // ID returns the ID of a Block, which is calculated by hashing the
   110  // concatenation of the block's parent's ID, nonce, and the result of the
   111  // b.MerkleRoot(). It is equivalent to calling block.Header().ID()
   112  func (b Block) ID() BlockID {
   113  	return b.Header().ID()
   114  }
   115  
   116  // MerkleRoot calculates the Merkle root of a Block. The leaves of the Merkle
   117  // tree are composed of the miner outputs (one leaf per payout), and the
   118  // transactions (one leaf per transaction).
   119  func (b Block) MerkleRoot() crypto.Hash {
   120  	tree := crypto.NewTree()
   121  	var buf bytes.Buffer
   122  	e := encoding.NewEncoder(&buf)
   123  	for _, payout := range b.MinerPayouts {
   124  		payout.MarshalSia(e)
   125  		tree.Push(buf.Bytes())
   126  		buf.Reset()
   127  	}
   128  	for _, txn := range b.Transactions {
   129  		txn.MarshalSia(e)
   130  		tree.Push(buf.Bytes())
   131  		buf.Reset()
   132  	}
   133  
   134  	// Sanity check - verify that this root is the same as the root provided in
   135  	// the old implementation.
   136  	if build.DEBUG {
   137  		verifyTree := crypto.NewTree()
   138  		for _, payout := range b.MinerPayouts {
   139  			verifyTree.PushObject(payout)
   140  		}
   141  		for _, txn := range b.Transactions {
   142  			verifyTree.PushObject(txn)
   143  		}
   144  		if tree.Root() != verifyTree.Root() {
   145  			panic("Block MerkleRoot implementation is broken")
   146  		}
   147  	}
   148  
   149  	return tree.Root()
   150  }
   151  
   152  // MinerPayoutID returns the ID of the miner payout at the given index, which
   153  // is calculated by hashing the concatenation of the BlockID and the payout
   154  // index.
   155  func (b Block) MinerPayoutID(i uint64) SiacoinOutputID {
   156  	return SiacoinOutputID(crypto.HashAll(
   157  		b.ID(),
   158  		i,
   159  	))
   160  }