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 }