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 { func CalcDifficulty(block, parent *types.Block) *big.Int {
diff := new(big.Int) diff := new(big.Int)
adjust := new(big.Int).Rsh(parent.Difficulty(), 10) //adjust := new(big.Int).Rsh(parent.Difficulty(), 10)
if block.Time() >= parent.Time()+8 { //if block.Time() >= parent.Time()+8 {
diff.Sub(parent.Difficulty(), adjust) adjust := new(big.Int).Div(parent.Difficulty(), big.NewInt(2048))
} else { if (block.Time() - parent.Time()) < 8 {
diff.Add(parent.Difficulty(), adjust) diff.Add(parent.Difficulty(), adjust)
} else {
diff.Sub(parent.Difficulty(), adjust)
} }
return diff return diff

View File

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

View File

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

View File

@ -31,26 +31,48 @@ func NewVm(env Environment) VirtualMachine {
} }
var ( var (
GasStep = big.NewInt(1) GasQuickStep = big.NewInt(2)
GasSha = big.NewInt(10) GasFastestStep = big.NewInt(3)
GasSLoad = big.NewInt(20) GasFastStep = big.NewInt(5)
GasSStore = big.NewInt(100) GasMidStep = big.NewInt(8)
GasSStoreRefund = big.NewInt(100) GasSlowStep = big.NewInt(10)
GasBalance = big.NewInt(20) GasExtStep = big.NewInt(20)
GasCreate = big.NewInt(100)
GasCall = big.NewInt(20) GasStorageGet = big.NewInt(50)
GasCreateByte = big.NewInt(5) GasStorageAdd = big.NewInt(20000)
GasSha3Byte = big.NewInt(10) GasStorageMod = big.NewInt(5000)
GasSha256Byte = big.NewInt(50) GasLogBase = big.NewInt(2000)
GasRipemdByte = big.NewInt(50) GasLogTopic = big.NewInt(2000)
GasMemory = big.NewInt(1) GasLogData = big.NewInt(8)
GasData = big.NewInt(5) GasCreate = big.NewInt(32000)
GasTx = big.NewInt(500) GasCreateByte = big.NewInt(300)
GasLog = big.NewInt(32) GasCall = big.NewInt(40)
GasSha256 = big.NewInt(50) GasCallValueTransfer = big.NewInt(6700)
GasRipemd = big.NewInt(50) GasCallNewAccount = big.NewInt(25000)
GasEcrecover = big.NewInt(500) GasReturn = big.NewInt(0)
GasMemCpy = big.NewInt(1) 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) Pow256 = ethutil.BigPow(2, 256)
@ -59,6 +81,8 @@ var (
U256 = ethutil.U256 U256 = ethutil.U256
S256 = ethutil.S256 S256 = ethutil.S256
Zero = ethutil.Big0
) )
const MaxCallDepth = 1025 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) { type req struct {
gas := new(big.Int) stack int
addStepGasUsage := func(amount *big.Int) { gas *big.Int
if amount.Cmp(ethutil.Big0) >= 0 { }
gas.Add(gas, amount)
} 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 // Stack Check, memory resize & gas phase
switch op { 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: case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2) n := int(op - SWAP1 + 2)
stack.require(n) stack.require(n)
@ -800,112 +870,83 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
n := int(op - LOG0) n := int(op - LOG0)
stack.require(n + 2) stack.require(n + 2)
gas.Set(GasLog)
addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog))
mSize, mStart := stack.Peekn() 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) newMemSize = calcMemSize(mStart, mSize)
case EXP: case EXP:
stack.require(2) gas.Add(gas, big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes())+1)))
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
case SSTORE: case SSTORE:
stack.require(2) stack.require(2)
var mult *big.Int var g *big.Int
y, x := stack.Peekn() y, x := stack.Peekn()
val := statedb.GetState(context.Address(), x.Bytes()) val := statedb.GetState(context.Address(), x.Bytes())
if len(val) == 0 && len(y.Bytes()) > 0 { if len(val) == 0 && len(y.Bytes()) > 0 {
// 0 => non 0 // 0 => non 0
mult = ethutil.Big3 g = GasStorageAdd
} else if len(val) > 0 && len(y.Bytes()) == 0 { } 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 { } else {
// non 0 => non 0 (or 0 => 0) // non 0 => non 0 (or 0 => 0)
mult = ethutil.Big1 g = GasStorageMod
} }
gas.Set(new(big.Int).Mul(mult, GasSStore)) gas.Set(g)
case BALANCE:
stack.require(1)
gas.Set(GasBalance)
case MSTORE:
stack.require(2)
newMemSize = calcMemSize(stack.Peek(), u256(32)) newMemSize = calcMemSize(stack.Peek(), u256(32))
case MLOAD: case MLOAD:
stack.require(1)
newMemSize = calcMemSize(stack.Peek(), u256(32)) newMemSize = calcMemSize(stack.Peek(), u256(32))
case MSTORE8: case MSTORE8:
stack.require(2)
newMemSize = calcMemSize(stack.Peek(), u256(1)) newMemSize = calcMemSize(stack.Peek(), u256(1))
case RETURN: case RETURN:
stack.require(2)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
case SHA3: case SHA3:
stack.require(2)
gas.Set(GasSha)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) 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: case CALLDATACOPY:
stack.require(3)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-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: case CODECOPY:
stack.require(3)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-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]) 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: case CALL, CALLCODE:
stack.require(7) gas.Add(gas, stack.data[stack.Len()-1])
gas.Set(GasCall)
addStepGasUsage(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]) x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7])
y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5]) y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5])
newMemSize = ethutil.BigMax(x, y) 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]) 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 { if newMemSize.Cmp(ethutil.Big0) > 0 {
newMemSize.Add(newMemSize, u256(31)) newMemSize.Add(newMemSize, u256(31))
newMemSize.Div(newMemSize, u256(32)) 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 { if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
memGasUsage.Mul(GasMemory, memGasUsage) memGasUsage.Mul(GasMemWord, memGasUsage)
memGasUsage.Div(memGasUsage, u256(32)) memGasUsage.Div(memGasUsage, u256(32))
addStepGasUsage(memGasUsage) gas.Add(gas, memGasUsage)
} }
} }