New gas prices model

This commit is contained in:
obscuren 2015-03-02 16:32:02 +01:00
parent 73c52d1677
commit b383ff0b96
5 changed files with 193 additions and 120 deletions

View File

@ -28,11 +28,13 @@ type StateQuery interface {
func CalcDifficulty(block, parent *types.Block) *big.Int {
diff := new(big.Int)
adjust := new(big.Int).Rsh(parent.Difficulty(), 10)
if block.Time() >= parent.Time()+8 {
diff.Sub(parent.Difficulty(), adjust)
} else {
//adjust := new(big.Int).Rsh(parent.Difficulty(), 10)
//if block.Time() >= parent.Time()+8 {
adjust := new(big.Int).Div(parent.Difficulty(), big.NewInt(2048))
if (block.Time() - parent.Time()) < 8 {
diff.Add(parent.Difficulty(), adjust)
} else {
diff.Sub(parent.Difficulty(), adjust)
}
return diff

View File

@ -12,6 +12,12 @@ import (
const tryJit = false
var (
GasTx = big.NewInt(21000)
GasTxNonZeroByte = big.NewInt(37)
GasTxZeroByte = big.NewInt(2)
)
/*
* The State transitioning model
*
@ -170,7 +176,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
//sender.Nonce += 1
// Transaction gas
if err = self.UseGas(vm.GasTx); err != nil {
if err = self.UseGas(GasTx); err != nil {
return
}
@ -178,9 +184,9 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
var dgas int64
for _, byt := range self.data {
if byt != 0 {
dgas += vm.GasData.Int64()
dgas += GasTxNonZeroByte.Int64()
} else {
dgas += 1 // This is 1/5. If GasData changes this fails
dgas += GasTxZeroByte.Int64()
}
}
if err = self.UseGas(big.NewInt(dgas)); err != nil {

View File

@ -32,23 +32,23 @@ func PrecompiledContracts() map[string]*PrecompiledAccount {
// SHA256
string(ethutil.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int {
n := big.NewInt(int64(l+31)/32 + 1)
n.Mul(n, GasSha256)
return n
n := big.NewInt(int64(l+31) / 32)
n.Mul(n, GasSha256Word)
return n.Add(n, GasSha256Base)
}, sha256Func},
// RIPEMD160
string(ethutil.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
n := big.NewInt(int64(l+31)/32 + 1)
n.Mul(n, GasRipemd)
return n
n := big.NewInt(int64(l+31) / 32)
n.Mul(n, GasRipemdWord)
return n.Add(n, GasRipemdBase)
}, ripemd160Func},
string(ethutil.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int {
n := big.NewInt(int64(l+31)/32 + 1)
n.Mul(n, GasMemCpy)
n := big.NewInt(int64(l+31) / 32)
n.Mul(n, GasIdentityWord)
return n
return n.Add(n, GasIdentityBase)
}, memCpy},
}
}

View File

@ -31,26 +31,48 @@ func NewVm(env Environment) VirtualMachine {
}
var (
GasStep = big.NewInt(1)
GasSha = big.NewInt(10)
GasSLoad = big.NewInt(20)
GasSStore = big.NewInt(100)
GasSStoreRefund = big.NewInt(100)
GasBalance = big.NewInt(20)
GasCreate = big.NewInt(100)
GasCall = big.NewInt(20)
GasCreateByte = big.NewInt(5)
GasSha3Byte = big.NewInt(10)
GasSha256Byte = big.NewInt(50)
GasRipemdByte = big.NewInt(50)
GasMemory = big.NewInt(1)
GasData = big.NewInt(5)
GasTx = big.NewInt(500)
GasLog = big.NewInt(32)
GasSha256 = big.NewInt(50)
GasRipemd = big.NewInt(50)
GasEcrecover = big.NewInt(500)
GasMemCpy = big.NewInt(1)
GasQuickStep = big.NewInt(2)
GasFastestStep = big.NewInt(3)
GasFastStep = big.NewInt(5)
GasMidStep = big.NewInt(8)
GasSlowStep = big.NewInt(10)
GasExtStep = big.NewInt(20)
GasStorageGet = big.NewInt(50)
GasStorageAdd = big.NewInt(20000)
GasStorageMod = big.NewInt(5000)
GasLogBase = big.NewInt(2000)
GasLogTopic = big.NewInt(2000)
GasLogData = big.NewInt(8)
GasCreate = big.NewInt(32000)
GasCreateByte = big.NewInt(300)
GasCall = big.NewInt(40)
GasCallValueTransfer = big.NewInt(6700)
GasCallNewAccount = big.NewInt(25000)
GasReturn = big.NewInt(0)
GasStop = big.NewInt(0)
GasJumpDest = big.NewInt(1)
RefundStorage = big.NewInt(15000)
RefundSuicide = big.NewInt(24000)
GasMemWord = big.NewInt(3)
GasQuadCoeffWord = big.NewInt(1)
GasContractByte = big.NewInt(200)
GasTransaction = big.NewInt(21000)
GasTxDataNonzeroByte = big.NewInt(37)
GasTxZeroByte = big.NewInt(2)
GasSha3Base = big.NewInt(30)
GasSha3Word = big.NewInt(6)
GasSha256Base = big.NewInt(60)
GasSha256Word = big.NewInt(12)
GasRipemdBase = big.NewInt(600)
GasRipemdWord = big.NewInt(12)
GasEcrecover = big.NewInt(3000)
GasIdentityBase = big.NewInt(15)
GasIdentityWord = big.NewInt(3)
GasCopyWord = big.NewInt(3)
Pow256 = ethutil.BigPow(2, 256)
@ -59,6 +81,8 @@ var (
U256 = ethutil.U256
S256 = ethutil.S256
Zero = ethutil.Big0
)
const MaxCallDepth = 1025

209
vm/vm.go
View File

@ -769,27 +769,97 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
}
}
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int) {
gas := new(big.Int)
addStepGasUsage := func(amount *big.Int) {
if amount.Cmp(ethutil.Big0) >= 0 {
gas.Add(gas, amount)
}
type req struct {
stack int
gas *big.Int
}
var _baseCheck = map[OpCode]req{
// Req Stack Gas price
ADD: {2, GasFastestStep},
LT: {2, GasFastestStep},
GT: {2, GasFastestStep},
SLT: {2, GasFastestStep},
SGT: {2, GasFastestStep},
EQ: {2, GasFastestStep},
ISZERO: {1, GasFastestStep},
SUB: {2, GasFastestStep},
AND: {2, GasFastestStep},
OR: {2, GasFastestStep},
XOR: {2, GasFastestStep},
NOT: {1, GasFastestStep},
BYTE: {2, GasFastestStep},
CALLDATALOAD: {1, GasFastestStep},
CALLDATACOPY: {3, GasFastestStep},
MLOAD: {1, GasFastestStep},
MSTORE: {2, GasFastestStep},
MSTORE8: {2, GasFastestStep},
CODECOPY: {3, GasFastestStep},
MUL: {2, GasFastStep},
DIV: {2, GasFastStep},
SDIV: {2, GasFastStep},
MOD: {2, GasFastStep},
SMOD: {2, GasFastStep},
SIGNEXTEND: {2, GasFastStep},
ADDMOD: {3, GasMidStep},
MULMOD: {3, GasMidStep},
JUMP: {1, GasMidStep},
JUMPI: {2, GasSlowStep},
EXP: {2, GasSlowStep},
ADDRESS: {0, GasQuickStep},
ORIGIN: {0, GasQuickStep},
CALLER: {0, GasQuickStep},
CALLVALUE: {0, GasQuickStep},
CODESIZE: {0, GasQuickStep},
GASPRICE: {0, GasQuickStep},
COINBASE: {0, GasQuickStep},
TIMESTAMP: {0, GasQuickStep},
NUMBER: {0, GasQuickStep},
DIFFICULTY: {0, GasQuickStep},
GASLIMIT: {0, GasQuickStep},
POP: {0, GasQuickStep},
PC: {0, GasQuickStep},
MSIZE: {0, GasQuickStep},
GAS: {0, GasQuickStep},
BLOCKHASH: {1, GasExtStep},
BALANCE: {0, GasExtStep},
EXTCODESIZE: {1, GasExtStep},
EXTCODECOPY: {4, GasExtStep},
SLOAD: {1, GasStorageGet},
SSTORE: {2, Zero},
SHA3: {1, GasSha3Base},
CREATE: {3, GasCreate},
CALL: {7, GasCall},
CALLCODE: {7, GasCall},
JUMPDEST: {0, GasJumpDest},
SUICIDE: {1, Zero},
RETURN: {2, Zero},
}
func baseCheck(op OpCode, stack *Stack, gas *big.Int) {
if r, ok := _baseCheck[op]; ok {
stack.require(r.stack)
gas.Add(gas, r.gas)
}
}
addStepGasUsage(GasStep)
func toWordSize(size *big.Int) *big.Int {
tmp := new(big.Int)
tmp.Add(tmp, u256(31))
tmp.Div(tmp, u256(32))
return tmp
}
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int) {
var (
gas = new(big.Int)
newMemSize *big.Int = new(big.Int)
)
baseCheck(op, stack, gas)
var newMemSize *big.Int = ethutil.Big0
var additionalGas *big.Int = new(big.Int)
// Stack Check, memory resize & gas phase
switch op {
// Stack checks only
case ISZERO, CALLDATALOAD, POP, JUMP, NOT, EXTCODESIZE, BLOCKHASH: // 1
stack.require(1)
case JUMPI, ADD, SUB, DIV, MUL, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
stack.require(2)
case ADDMOD, MULMOD: // 3
stack.require(3)
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
stack.require(n)
@ -800,112 +870,83 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
n := int(op - LOG0)
stack.require(n + 2)
gas.Set(GasLog)
addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog))
mSize, mStart := stack.Peekn()
addStepGasUsage(mSize)
gas.Add(gas, GasLogBase)
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic))
gas.Add(gas, new(big.Int).Mul(mSize, GasLogData))
newMemSize = calcMemSize(mStart, mSize)
case EXP:
stack.require(2)
gas.Set(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()) + 1)))
// Gas only
case STOP:
gas.Set(ethutil.Big0)
case SUICIDE:
stack.require(1)
gas.Set(ethutil.Big0)
case SLOAD:
stack.require(1)
gas.Set(GasSLoad)
// Memory resize & Gas
gas.Add(gas, big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes())+1)))
case SSTORE:
stack.require(2)
var mult *big.Int
var g *big.Int
y, x := stack.Peekn()
val := statedb.GetState(context.Address(), x.Bytes())
if len(val) == 0 && len(y.Bytes()) > 0 {
// 0 => non 0
mult = ethutil.Big3
g = GasStorageAdd
} else if len(val) > 0 && len(y.Bytes()) == 0 {
statedb.Refund(self.env.Origin(), GasSStoreRefund)
statedb.Refund(self.env.Origin(), RefundStorage)
mult = ethutil.Big0
g = GasStorageMod
} else {
// non 0 => non 0 (or 0 => 0)
mult = ethutil.Big1
g = GasStorageMod
}
gas.Set(new(big.Int).Mul(mult, GasSStore))
case BALANCE:
stack.require(1)
gas.Set(GasBalance)
case MSTORE:
stack.require(2)
gas.Set(g)
newMemSize = calcMemSize(stack.Peek(), u256(32))
case MLOAD:
stack.require(1)
newMemSize = calcMemSize(stack.Peek(), u256(32))
case MSTORE8:
stack.require(2)
newMemSize = calcMemSize(stack.Peek(), u256(1))
case RETURN:
stack.require(2)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
case SHA3:
stack.require(2)
gas.Set(GasSha)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
additionalGas.Set(stack.data[stack.Len()-2])
words := toWordSize(stack.data[stack.Len()-2])
gas.Add(gas, words.Mul(words, GasSha3Word))
case CALLDATACOPY:
stack.require(3)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
additionalGas.Set(stack.data[stack.Len()-3])
words := toWordSize(stack.data[stack.Len()-3])
gas.Add(gas, words.Mul(words, GasCopyWord))
case CODECOPY:
stack.require(3)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
additionalGas.Set(stack.data[stack.Len()-3])
case EXTCODECOPY:
stack.require(4)
words := toWordSize(stack.data[stack.Len()-3])
gas.Add(gas, words.Mul(words, GasCopyWord))
case EXTCODECOPY:
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4])
additionalGas.Set(stack.data[stack.Len()-4])
words := toWordSize(stack.data[stack.Len()-4])
gas.Add(gas, words.Mul(words, GasCopyWord))
case CREATE:
size := new(big.Int).Set(stack.data[stack.Len()-2])
gas.Add(gas, size.Mul(size, GasCreateByte))
case CALL, CALLCODE:
stack.require(7)
gas.Set(GasCall)
addStepGasUsage(stack.data[stack.Len()-1])
gas.Add(gas, stack.data[stack.Len()-1])
if op == CALL {
if self.env.State().GetStateObject(stack.data[stack.Len()-2].Bytes()) == nil {
gas.Add(gas, GasCallNewAccount)
}
if len(stack.data[stack.Len()].Bytes()) > 0 {
gas.Add(gas, GasCallValueTransfer)
}
}
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 = ethutil.BigMax(x, y)
case CREATE:
stack.require(3)
gas.Set(GasCreate)
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
}
switch op {
case CALLDATACOPY, CODECOPY, EXTCODECOPY:
additionalGas.Add(additionalGas, u256(31))
additionalGas.Div(additionalGas, u256(32))
addStepGasUsage(additionalGas)
case SHA3:
additionalGas.Add(additionalGas, u256(31))
additionalGas.Div(additionalGas, u256(32))
additionalGas.Mul(additionalGas, GasSha3Byte)
addStepGasUsage(additionalGas)
}
if newMemSize.Cmp(ethutil.Big0) > 0 {
newMemSize.Add(newMemSize, u256(31))
newMemSize.Div(newMemSize, u256(32))
@ -913,10 +954,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
memGasUsage.Mul(GasMemory, memGasUsage)
memGasUsage.Mul(GasMemWord, memGasUsage)
memGasUsage.Div(memGasUsage, u256(32))
addStepGasUsage(memGasUsage)
gas.Add(gas, memGasUsage)
}
}