github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/core/chain_util.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "bytes" 21 "math/big" 22 "time" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/core/types" 26 "github.com/ethereum/go-ethereum/logger" 27 "github.com/ethereum/go-ethereum/logger/glog" 28 "github.com/ethereum/go-ethereum/params" 29 "github.com/ethereum/go-ethereum/rlp" 30 ) 31 32 var ( 33 blockHashPre = []byte("block-hash-") 34 blockNumPre = []byte("block-num-") 35 ExpDiffPeriod = big.NewInt(100000) 36 ) 37 38 // CalcDifficulty is the difficulty adjustment algorithm. It returns 39 // the difficulty that a new block b should have when created at time 40 // given the parent block's time and difficulty. 41 func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { 42 diff := new(big.Int) 43 adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor) 44 bigTime := new(big.Int) 45 bigParentTime := new(big.Int) 46 47 bigTime.SetUint64(time) 48 bigParentTime.SetUint64(parentTime) 49 50 if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 { 51 diff.Add(parentDiff, adjust) 52 } else { 53 diff.Sub(parentDiff, adjust) 54 } 55 if diff.Cmp(params.MinimumDifficulty) < 0 { 56 diff = params.MinimumDifficulty 57 } 58 59 periodCount := new(big.Int).Add(parentNumber, common.Big1) 60 periodCount.Div(periodCount, ExpDiffPeriod) 61 if periodCount.Cmp(common.Big1) > 0 { 62 // diff = diff + 2^(periodCount - 2) 63 expDiff := periodCount.Sub(periodCount, common.Big2) 64 expDiff.Exp(common.Big2, expDiff, nil) 65 diff.Add(diff, expDiff) 66 diff = common.BigMax(diff, params.MinimumDifficulty) 67 } 68 69 return diff 70 } 71 72 // CalcTD computes the total difficulty of block. 73 func CalcTD(block, parent *types.Block) *big.Int { 74 if parent == nil { 75 return block.Difficulty() 76 } 77 d := block.Difficulty() 78 d.Add(d, parent.Td) 79 return d 80 } 81 82 // CalcGasLimit computes the gas limit of the next block after parent. 83 // The result may be modified by the caller. 84 // This is miner strategy, not consensus protocol. 85 func CalcGasLimit(parent *types.Block) *big.Int { 86 // contrib = (parentGasUsed * 3 / 2) / 1024 87 contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3)) 88 contrib = contrib.Div(contrib, big.NewInt(2)) 89 contrib = contrib.Div(contrib, params.GasLimitBoundDivisor) 90 91 // decay = parentGasLimit / 1024 -1 92 decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor) 93 decay.Sub(decay, big.NewInt(1)) 94 95 /* 96 strategy: gasLimit of block-to-mine is set based on parent's 97 gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we 98 increase it, otherwise lower it (or leave it unchanged if it's right 99 at that usage) the amount increased/decreased depends on how far away 100 from parentGasLimit * (2/3) parentGasUsed is. 101 */ 102 gl := new(big.Int).Sub(parent.GasLimit(), decay) 103 gl = gl.Add(gl, contrib) 104 gl.Set(common.BigMax(gl, params.MinGasLimit)) 105 106 // however, if we're now below the target (GenesisGasLimit) we increase the 107 // limit as much as we can (parentGasLimit / 1024 -1) 108 if gl.Cmp(params.GenesisGasLimit) < 0 { 109 gl.Add(parent.GasLimit(), decay) 110 gl.Set(common.BigMin(gl, params.GenesisGasLimit)) 111 } 112 return gl 113 } 114 115 // GetBlockByHash returns the block corresponding to the hash or nil if not found 116 func GetBlockByHash(db common.Database, hash common.Hash) *types.Block { 117 data, _ := db.Get(append(blockHashPre, hash[:]...)) 118 if len(data) == 0 { 119 return nil 120 } 121 var block types.StorageBlock 122 if err := rlp.Decode(bytes.NewReader(data), &block); err != nil { 123 glog.V(logger.Error).Infof("invalid block RLP for hash %x: %v", hash, err) 124 return nil 125 } 126 return (*types.Block)(&block) 127 } 128 129 // GetBlockByHash returns the canonical block by number or nil if not found 130 func GetBlockByNumber(db common.Database, number uint64) *types.Block { 131 key, _ := db.Get(append(blockNumPre, big.NewInt(int64(number)).Bytes()...)) 132 if len(key) == 0 { 133 return nil 134 } 135 136 return GetBlockByHash(db, common.BytesToHash(key)) 137 } 138 139 // WriteCanonNumber writes the canonical hash for the given block 140 func WriteCanonNumber(db common.Database, block *types.Block) error { 141 key := append(blockNumPre, block.Number().Bytes()...) 142 err := db.Put(key, block.Hash().Bytes()) 143 if err != nil { 144 return err 145 } 146 return nil 147 } 148 149 // WriteHead force writes the current head 150 func WriteHead(db common.Database, block *types.Block) error { 151 err := WriteCanonNumber(db, block) 152 if err != nil { 153 return err 154 } 155 err = db.Put([]byte("LastBlock"), block.Hash().Bytes()) 156 if err != nil { 157 return err 158 } 159 return nil 160 } 161 162 // WriteBlock writes a block to the database 163 func WriteBlock(db common.Database, block *types.Block) error { 164 tstart := time.Now() 165 166 enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block)) 167 key := append(blockHashPre, block.Hash().Bytes()...) 168 err := db.Put(key, enc) 169 if err != nil { 170 glog.Fatal("db write fail:", err) 171 return err 172 } 173 174 if glog.V(logger.Debug) { 175 glog.Infof("wrote block #%v %s. Took %v\n", block.Number(), common.PP(block.Hash().Bytes()), time.Since(tstart)) 176 } 177 178 return nil 179 }