github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/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  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  
    12  	"github.com/NebulousLabs/Sia/crypto"
    13  	"github.com/NebulousLabs/Sia/encoding"
    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, when encoded, is an 80-byte constant size field
    39  	// containing enough information to do headers-first block downloading.
    40  	// Hashing the header results in the block ID.
    41  	BlockHeader struct {
    42  		ParentID   BlockID     `json:"parentid"`
    43  		Nonce      BlockNonce  `json:"nonce"`
    44  		Timestamp  Timestamp   `json:"timestamp"`
    45  		MerkleRoot crypto.Hash `json:"merkleroot"`
    46  	}
    47  
    48  	BlockHeight uint64
    49  	BlockID     crypto.Hash
    50  	BlockNonce  [8]byte
    51  )
    52  
    53  // CalculateCoinbase calculates the coinbase for a given height. The coinbase
    54  // equation is:
    55  //
    56  //     coinbase := max(InitialCoinbase - height, MinimumCoinbase) * SiacoinPrecision
    57  func CalculateCoinbase(height BlockHeight) Currency {
    58  	base := InitialCoinbase - uint64(height)
    59  	if uint64(height) > InitialCoinbase || base < MinimumCoinbase {
    60  		base = MinimumCoinbase
    61  	}
    62  	return NewCurrency64(base).Mul(SiacoinPrecision)
    63  }
    64  
    65  // CalculateNumSiacoins calculates the number of siacoins in circulation at a
    66  // given height.
    67  func CalculateNumSiacoins(height BlockHeight) Currency {
    68  	deflationBlocks := BlockHeight(InitialCoinbase - MinimumCoinbase)
    69  	avgDeflationSiacoins := CalculateCoinbase(0).Add(CalculateCoinbase(height)).Div(NewCurrency64(2))
    70  	if height <= deflationBlocks {
    71  		deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(height + 1)))
    72  		return deflationSiacoins
    73  	}
    74  	deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(deflationBlocks + 1)))
    75  	trailingSiacoins := NewCurrency64(uint64(height - deflationBlocks)).Mul(CalculateCoinbase(height))
    76  	return deflationSiacoins.Add(trailingSiacoins)
    77  }
    78  
    79  // ID returns the ID of a Block, which is calculated by hashing the header.
    80  func (h BlockHeader) ID() BlockID {
    81  	return BlockID(crypto.HashObject(h))
    82  }
    83  
    84  // CalculateSubsidy takes a block and a height and determines the block
    85  // subsidy.
    86  func (b Block) CalculateSubsidy(height BlockHeight) Currency {
    87  	subsidy := CalculateCoinbase(height)
    88  	for _, txn := range b.Transactions {
    89  		for _, fee := range txn.MinerFees {
    90  			subsidy = subsidy.Add(fee)
    91  		}
    92  	}
    93  	return subsidy
    94  }
    95  
    96  // Header returns the header of a block.
    97  func (b Block) Header() BlockHeader {
    98  	return BlockHeader{
    99  		ParentID:   b.ParentID,
   100  		Nonce:      b.Nonce,
   101  		Timestamp:  b.Timestamp,
   102  		MerkleRoot: b.MerkleRoot(),
   103  	}
   104  }
   105  
   106  // ID returns the ID of a Block, which is calculated by hashing the
   107  // concatenation of the block's parent's ID, nonce, and the result of the
   108  // b.MerkleRoot(). It is equivalent to calling block.Header().ID()
   109  func (b Block) ID() BlockID {
   110  	return b.Header().ID()
   111  }
   112  
   113  // MerkleRoot calculates the Merkle root of a Block. The leaves of the Merkle
   114  // tree are composed of the Timestamp, the miner outputs (one leaf per
   115  // payout), and the transactions (one leaf per transaction).
   116  func (b Block) MerkleRoot() crypto.Hash {
   117  	tree := crypto.NewTree()
   118  	for _, payout := range b.MinerPayouts {
   119  		tree.PushObject(payout)
   120  	}
   121  	for _, txn := range b.Transactions {
   122  		tree.PushObject(txn)
   123  	}
   124  	return tree.Root()
   125  }
   126  
   127  // MinerPayoutID returns the ID of the miner payout at the given index, which
   128  // is calculated by hashing the concatenation of the BlockID and the payout
   129  // index.
   130  func (b Block) MinerPayoutID(i uint64) SiacoinOutputID {
   131  	return SiacoinOutputID(crypto.HashAll(
   132  		b.ID(),
   133  		i,
   134  	))
   135  }
   136  
   137  // MarshalSia implements the encoding.SiaMarshaler interface.
   138  func (b Block) MarshalSia(w io.Writer) error {
   139  	w.Write(b.ParentID[:])
   140  	w.Write(b.Nonce[:])
   141  	w.Write(encoding.EncUint64(uint64(b.Timestamp)))
   142  	return encoding.NewEncoder(w).EncodeAll(b.MinerPayouts, b.Transactions)
   143  }
   144  
   145  // UnmarshalSia implements the encoding.SiaUnmarshaler interface.
   146  func (b *Block) UnmarshalSia(r io.Reader) error {
   147  	io.ReadFull(r, b.ParentID[:])
   148  	io.ReadFull(r, b.Nonce[:])
   149  	tsBytes := make([]byte, 8)
   150  	io.ReadFull(r, tsBytes)
   151  	b.Timestamp = Timestamp(encoding.DecUint64(tsBytes))
   152  	return encoding.NewDecoder(r).DecodeAll(&b.MinerPayouts, &b.Transactions)
   153  }
   154  
   155  // MarshalJSON marshales a block id as a hex string.
   156  func (bid BlockID) MarshalJSON() ([]byte, error) {
   157  	return json.Marshal(bid.String())
   158  }
   159  
   160  // String prints the block id in hex.
   161  func (bid BlockID) String() string {
   162  	return fmt.Sprintf("%x", bid[:])
   163  }
   164  
   165  // UnmarshalJSON decodes the json hex string of the block id.
   166  func (bid *BlockID) UnmarshalJSON(b []byte) error {
   167  	if len(b) != crypto.HashSize*2+2 {
   168  		return crypto.ErrHashWrongLen
   169  	}
   170  
   171  	var bidBytes []byte
   172  	_, err := fmt.Sscanf(string(b[1:len(b)-1]), "%x", &bidBytes)
   173  	if err != nil {
   174  		return errors.New("could not unmarshal BlockID: " + err.Error())
   175  	}
   176  	copy(bid[:], bidBytes)
   177  	return nil
   178  }