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 }