[release/1.3.4] parmas, crypto, core, core/vm: homestead consensus protocol changes

* change gas cost for contract creating txs
* invalidate signature with s value greater than secp256k1 N / 2
* OOG contract creation if not enough gas to store code
* new difficulty adjustment algorithm
* new DELEGATECALL op code

Conflicts:
	core/vm/environment.go
	crypto/crypto.go
	crypto/secp256k1/secp256.go
	eth/api.go
This commit is contained in:
Gustav Simonsson
2015-11-27 15:40:29 +01:00
committed by Jeffrey Wilcke
parent 300f1e2abf
commit 61404979ed
54 changed files with 25877 additions and 11223 deletions

View File

@ -26,11 +26,13 @@ import (
type ContractRef interface {
ReturnGas(*big.Int, *big.Int)
Address() common.Address
SetAddress(common.Address)
Value() *big.Int
SetCode([]byte)
}
// Contract represents an ethereum contract in the state database. It contains
// the the contract code, calling arguments. Contract implements ContractReg
// the the contract code, calling arguments. Contract implements ContractRef
type Contract struct {
caller ContractRef
self ContractRef
@ -44,6 +46,8 @@ type Contract struct {
value, Gas, UsedGas, Price *big.Int
Args []byte
DelegateCall bool
}
// Create a new context for the given data items.
@ -113,6 +117,16 @@ func (c *Contract) Address() common.Address {
return c.self.Address()
}
// SetAddress sets the contracts address
func (c *Contract) SetAddress(addr common.Address) {
c.self.SetAddress(addr)
}
// Value returns the contracts value (sent to it from it's caller)
func (c *Contract) Value() *big.Int {
return c.value
}
// SetCode sets the code to the contract
func (self *Contract) SetCode(code []byte) {
self.Code = code

View File

@ -93,7 +93,8 @@ func ecrecoverFunc(in []byte) []byte {
vbig := common.Bytes2Big(in[32:64])
v := byte(vbig.Uint64())
if !crypto.ValidateSignatureValues(v, r, s) {
// tighter sig s values in homestead only apply to tx sigs
if !crypto.ValidateSignatureValues(v, r, s, false) {
glog.V(logger.Debug).Infof("EC RECOVER FAIL: v, r or s value invalid")
return nil
}

View File

@ -70,6 +70,8 @@ type Environment interface {
Call(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error)
// Take another's contract code and execute within our own context
CallCode(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error)
// Same as CallCode except sender and value is propagated from parent to child scope
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
// Create a new contract
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
}
@ -119,6 +121,9 @@ type Account interface {
SetNonce(uint64)
Balance() *big.Int
Address() common.Address
SetAddress(common.Address)
ReturnGas(*big.Int, *big.Int)
SetCode([]byte)
EachStorage(cb func(key, value []byte))
Value() *big.Int
}

View File

@ -24,4 +24,5 @@ import (
)
var OutOfGasError = errors.New("Out of gas")
var CodeStoreOutOfGasError = errors.New("Contract creation code storage out of gas")
var DepthError = fmt.Errorf("Max call depth exceeded (%d)", params.CallCreateDepth)

View File

@ -136,6 +136,7 @@ var _baseCheck = map[OpCode]req{
CREATE: {3, params.CreateGas, 1},
CALL: {7, params.CallGas, 1},
CALLCODE: {7, params.CallGas, 1},
DELEGATECALL: {6, params.CallGas, 1},
JUMPDEST: {0, params.JumpdestGas, 0},
SUICIDE: {1, Zero, 0},
RETURN: {2, Zero, 0},

View File

@ -337,7 +337,13 @@ func opOrigin(instr instruction, pc *uint64, env Environment, contract *Contract
}
func opCaller(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
stack.push(common.Bytes2Big(contract.caller.Address().Bytes()))
var bigAddr *big.Int
if contract.DelegateCall {
bigAddr = env.Origin().Big()
} else {
bigAddr = contract.caller.Address().Big()
}
stack.push(bigAddr)
}
func opCallValue(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
@ -485,7 +491,6 @@ func opSload(instr instruction, pc *uint64, env Environment, contract *Contract,
func opSstore(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
loc := common.BigToHash(stack.pop())
val := stack.pop()
env.Db().SetState(contract.Address(), loc, common.BigToHash(val))
}
@ -509,31 +514,6 @@ func opGas(instr instruction, pc *uint64, env Environment, contract *Contract, m
}
func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
var (
value = stack.pop()
offset, size = stack.pop(), stack.pop()
input = memory.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(contract.Gas)
addr common.Address
ret []byte
suberr error
)
contract.UseGas(contract.Gas)
ret, addr, suberr = env.Create(contract, input, gas, contract.Price, value)
if suberr != nil {
stack.push(new(big.Int))
} else {
// gas < len(ret) * Createinstr.dataGas == NO_CODE
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, params.CreateDataGas)
if contract.UseGas(dataGas) {
env.Db().SetCode(addr, ret)
}
stack.push(addr.Big())
}
}
func opCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
@ -598,6 +578,21 @@ func opCallCode(instr instruction, pc *uint64, env Environment, contract *Contra
}
}
func opDelegateCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(to)
args := memory.Get(inOffset.Int64(), inSize.Int64())
ret, err := env.DelegateCall(contract, toAddr, args, gas, contract.Price)
if err != nil {
stack.push(new(big.Int))
} else {
stack.push(big.NewInt(1))
memory.Set(outOffset.Uint64(), outSize.Uint64(), ret)
}
}
func opReturn(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
}
func opStop(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {

View File

@ -62,9 +62,10 @@ func init() {
jumpTable[PC] = jumpPtr{nil, true}
jumpTable[MSIZE] = jumpPtr{opMsize, true}
jumpTable[GAS] = jumpPtr{opGas, true}
jumpTable[CREATE] = jumpPtr{opCreate, true}
jumpTable[CREATE] = jumpPtr{nil, true}
jumpTable[CALL] = jumpPtr{opCall, true}
jumpTable[CALLCODE] = jumpPtr{opCallCode, true}
jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true}
jumpTable[LOG0] = jumpPtr{makeLog(0), true}
jumpTable[LOG1] = jumpPtr{makeLog(1), true}
jumpTable[LOG2] = jumpPtr{makeLog(2), true}

View File

@ -200,6 +200,7 @@ const (
CALL
CALLCODE
RETURN
DELEGATECALL
SUICIDE = 0xff
)
@ -349,11 +350,12 @@ var opCodeToString = map[OpCode]string{
LOG4: "LOG4",
// 0xf0 range
CREATE: "CREATE",
CALL: "CALL",
RETURN: "RETURN",
CALLCODE: "CALLCODE",
SUICIDE: "SUICIDE",
CREATE: "CREATE",
CALL: "CALL",
RETURN: "RETURN",
CALLCODE: "CALLCODE",
DELEGATECALL: "DELEGATECALL",
SUICIDE: "SUICIDE",
PUSH: "PUSH",
DUP: "DUP",

View File

@ -101,6 +101,10 @@ func (self *Env) CallCode(caller vm.ContractRef, addr common.Address, data []byt
return core.CallCode(self, caller, addr, data, gas, price, value)
}
func (self *Env) DelegateCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) {
return core.DelegateCall(self, me, addr, data, gas, price)
}
func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
return core.Create(self, caller, data, gas, price, value)
}

View File

@ -160,7 +160,6 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) {
// Get the memory location of pc
op = contract.GetOp(pc)
// calculate the new memory size and gas price for the current executing opcode
newMemSize, cost, err = calculateGasAndSize(self.env, contract, caller, op, statedb, mem, stack)
if err != nil {
@ -177,7 +176,6 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) {
mem.Resize(newMemSize.Uint64())
// Add a log message
self.log(pc, op, contract.Gas, cost, mem, stack, contract, nil)
if opPtr := jumpTable[op]; opPtr.valid {
if opPtr.fn != nil {
opPtr.fn(instruction{}, &pc, self.env, contract, mem, stack)
@ -201,6 +199,35 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) {
continue
}
case CREATE:
var (
value = stack.pop()
offset, size = stack.pop(), stack.pop()
input = mem.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(contract.Gas)
addr common.Address
ret []byte
suberr error
)
contract.UseGas(contract.Gas)
ret, addr, suberr = self.env.Create(contract, input, gas, contract.Price, value)
if suberr != nil {
stack.push(new(big.Int))
} else {
// gas < len(ret) * Createinstr.dataGas == NO_CODE
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, params.CreateDataGas)
if contract.UseGas(dataGas) {
self.env.Db().SetCode(addr, ret)
} else {
if params.IsHomestead(self.env.BlockNumber()) {
stack.push(new(big.Int))
return nil, CodeStoreOutOfGasError
}
}
stack.push(addr.Big())
}
case RETURN:
offset, size := stack.pop(), stack.pop()
ret := mem.GetPtr(offset.Int64(), size.Int64())
@ -345,6 +372,13 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
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)
case DELEGATECALL:
gas.Add(gas, stack.data[stack.len()-1])
x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6])
y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4])
newMemSize = common.BigMax(x, y)
}
quadMemGas(mem, newMemSize, gas)