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