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