// CalcDifficulty is the difficulty adjustment algorithm. It returns // the difficulty that a new block b should have when created at time // given the parent block's time and difficulty. func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { diff := new(big.Int) adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor) bigTime := new(big.Int) bigParentTime := new(big.Int) bigTime.SetUint64(time) bigParentTime.SetUint64(parentTime) if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 { diff.Add(parentDiff, adjust) } else { diff.Sub(parentDiff, adjust) } if diff.Cmp(params.MinimumDifficulty) < 0 { diff = params.MinimumDifficulty } periodCount := new(big.Int).Add(parentNumber, common.Big1) periodCount.Div(periodCount, ExpDiffPeriod) if periodCount.Cmp(common.Big1) > 0 { // diff = diff + 2^(periodCount - 2) expDiff := periodCount.Sub(periodCount, common.Big2) expDiff.Exp(common.Big2, expDiff, nil) diff.Add(diff, expDiff) diff = common.BigMax(diff, params.MinimumDifficulty) } return diff }
// CalcGasLimit computes the gas limit of the next block after parent. // The result may be modified by the caller. // This is miner strategy, not consensus protocol. func CalcGasLimit(parent *types.Block) *big.Int { // contrib = (parentGasUsed * 3 / 2) / 1024 contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3)) contrib = contrib.Div(contrib, big.NewInt(2)) contrib = contrib.Div(contrib, params.GasLimitBoundDivisor) // decay = parentGasLimit / 1024 -1 decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor) decay.Sub(decay, big.NewInt(1)) /* strategy: gasLimit of block-to-mine is set based on parent's gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we increase it, otherwise lower it (or leave it unchanged if it's right at that usage) the amount increased/decreased depends on how far away from parentGasLimit * (2/3) parentGasUsed is. */ gl := new(big.Int).Sub(parent.GasLimit(), decay) gl = gl.Add(gl, contrib) gl.Set(common.BigMax(gl, params.MinGasLimit)) // however, if we're now below the target (GenesisGasLimit) we increase the // limit as much as we can (parentGasLimit / 1024 -1) if gl.Cmp(params.GenesisGasLimit) < 0 { gl.Add(parent.GasLimit(), decay) gl.Set(common.BigMin(gl, params.GenesisGasLimit)) } return gl }
// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for // the operation. This does not reduce gas or resizes the memory. func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *stack) (*big.Int, *big.Int, error) { var ( gas = new(big.Int) newMemSize *big.Int = new(big.Int) ) err := baseCheck(op, stack, gas) if err != nil { return nil, nil, err } // stack Check, memory resize & gas phase switch op { case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) err := stack.require(n) if err != nil { return nil, nil, err } gas.Set(GasFastestStep) case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) err := stack.require(n) if err != nil { return nil, nil, err } gas.Set(GasFastestStep) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) err := stack.require(n + 2) if err != nil { return nil, nil, err } mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] gas.Add(gas, params.LogGas) gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas)) gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas)) newMemSize = calcMemSize(mStart, mSize) case EXP: gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas)) case SSTORE: err := stack.require(2) if err != nil { return nil, nil, err } var g *big.Int y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] val := statedb.GetState(contract.Address(), common.BigToHash(x)) // This checks for 3 scenario's and calculates gas accordingly // 1. From a zero-value address to a non-zero value (NEW VALUE) // 2. From a non-zero value address to a zero-value address (DELETE) // 3. From a nen-zero to a non-zero (CHANGE) if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { // 0 => non 0 g = params.SstoreSetGas } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { statedb.AddRefund(params.SstoreRefundGas) g = params.SstoreClearGas } else { // non 0 => non 0 (or 0 => 0) g = params.SstoreClearGas } gas.Set(g) case SUICIDE: if !statedb.IsDeleted(contract.Address()) { statedb.AddRefund(params.SuicideRefundGas) } case MLOAD: newMemSize = calcMemSize(stack.peek(), u256(32)) case MSTORE8: newMemSize = calcMemSize(stack.peek(), u256(1)) case MSTORE: newMemSize = calcMemSize(stack.peek(), u256(32)) case RETURN: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) case SHA3: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) words := toWordSize(stack.data[stack.len()-2]) gas.Add(gas, words.Mul(words, params.Sha3WordGas)) case CALLDATACOPY: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3]) gas.Add(gas, words.Mul(words, params.CopyGas)) case CODECOPY: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3]) gas.Add(gas, words.Mul(words, params.CopyGas)) case EXTCODECOPY: newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) words := toWordSize(stack.data[stack.len()-4]) gas.Add(gas, words.Mul(words, params.CopyGas)) case CREATE: newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) case CALL, CALLCODE: gas.Add(gas, stack.data[stack.len()-1]) if op == CALL { //if env.Db().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil { if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) { gas.Add(gas, params.CallNewAccountGas) } } if len(stack.data[stack.len()-3].Bytes()) > 0 { gas.Add(gas, params.CallValueTransferGas) } x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5]) newMemSize = common.BigMax(x, y) } quadMemGas(mem, newMemSize, gas) return newMemSize, gas, nil }
// jitCalculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for // the operation. This does not reduce gas or resizes the memory. func jitCalculateGasAndSize(env Environment, context *Context, caller ContextRef, instr instruction, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) { var ( gas = new(big.Int) newMemSize *big.Int = new(big.Int) ) err := jitBaseCheck(instr, stack, gas) if err != nil { return nil, nil, err } // stack Check, memory resize & gas phase switch op := instr.op; op { case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) err := stack.require(n) if err != nil { return nil, nil, err } gas.Set(GasFastestStep) case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) err := stack.require(n) if err != nil { return nil, nil, err } gas.Set(GasFastestStep) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) err := stack.require(n + 2) if err != nil { return nil, nil, err } mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] add := new(big.Int) gas.Add(gas, params.LogGas) gas.Add(gas, add.Mul(big.NewInt(int64(n)), params.LogTopicGas)) gas.Add(gas, add.Mul(mSize, params.LogDataGas)) newMemSize = calcMemSize(mStart, mSize) case EXP: gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas)) case SSTORE: err := stack.require(2) if err != nil { return nil, nil, err } var g *big.Int y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] val := statedb.GetState(context.Address(), common.BigToHash(x)) // This checks for 3 scenario's and calculates gas accordingly // 1. From a zero-value address to a non-zero value (NEW VALUE) // 2. From a non-zero value address to a zero-value address (DELETE) // 3. From a nen-zero to a non-zero (CHANGE) if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { // 0 => non 0 g = params.SstoreSetGas } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { statedb.Refund(params.SstoreRefundGas) g = params.SstoreClearGas } else { // non 0 => non 0 (or 0 => 0) g = params.SstoreClearGas } gas.Set(g) case SUICIDE: if !statedb.IsDeleted(context.Address()) { statedb.Refund(params.SuicideRefundGas) } case MLOAD: newMemSize = calcMemSize(stack.peek(), u256(32)) case MSTORE8: newMemSize = calcMemSize(stack.peek(), u256(1)) case MSTORE: newMemSize = calcMemSize(stack.peek(), u256(32)) case RETURN: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) case SHA3: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) words := toWordSize(stack.data[stack.len()-2]) gas.Add(gas, words.Mul(words, params.Sha3WordGas)) case CALLDATACOPY: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3]) gas.Add(gas, words.Mul(words, params.CopyGas)) case CODECOPY: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3]) gas.Add(gas, words.Mul(words, params.CopyGas)) case EXTCODECOPY: newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) words := toWordSize(stack.data[stack.len()-4]) gas.Add(gas, words.Mul(words, params.CopyGas)) case CREATE: newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) case CALL, CALLCODE: gas.Add(gas, stack.data[stack.len()-1]) if op == CALL { if env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil { gas.Add(gas, params.CallNewAccountGas) } } if len(stack.data[stack.len()-3].Bytes()) > 0 { gas.Add(gas, params.CallValueTransferGas) } x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5]) newMemSize = common.BigMax(x, y) } if newMemSize.Cmp(common.Big0) > 0 { newMemSizeWords := toWordSize(newMemSize) newMemSize.Mul(newMemSizeWords, u256(32)) if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { // be careful reusing variables here when changing. // The order has been optimised to reduce allocation oldSize := toWordSize(big.NewInt(int64(mem.Len()))) pow := new(big.Int).Exp(oldSize, common.Big2, Zero) linCoef := oldSize.Mul(oldSize, params.MemoryGas) quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv) oldTotalFee := new(big.Int).Add(linCoef, quadCoef) pow.Exp(newMemSizeWords, common.Big2, Zero) linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas) quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv) newTotalFee := linCoef.Add(linCoef, quadCoef) fee := newTotalFee.Sub(newTotalFee, oldTotalFee) gas.Add(gas, fee) } } return newMemSize, gas, nil }