diff options
author | Gustav Simonsson <gustav.simonsson@gmail.com> | 2015-11-27 22:40:29 +0800 |
---|---|---|
committer | Jeffrey Wilcke <geffobscura@gmail.com> | 2016-02-18 17:08:11 +0800 |
commit | 371871d685d54b916aef28de689d6f0af7822083 (patch) | |
tree | e704b02ba2ffd2d1164001885fba15106b0f7d94 /core/vm | |
parent | aa36a6ae4f24f07e2c470a21c93ff37ad5861982 (diff) | |
download | go-tangerine-371871d685d54b916aef28de689d6f0af7822083.tar.gz go-tangerine-371871d685d54b916aef28de689d6f0af7822083.tar.zst go-tangerine-371871d685d54b916aef28de689d6f0af7822083.zip |
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
Diffstat (limited to 'core/vm')
-rw-r--r-- | core/vm/contract.go | 16 | ||||
-rw-r--r-- | core/vm/contracts.go | 3 | ||||
-rw-r--r-- | core/vm/environment.go | 4 | ||||
-rw-r--r-- | core/vm/errors.go | 1 | ||||
-rw-r--r-- | core/vm/gas.go | 1 | ||||
-rw-r--r-- | core/vm/instructions.go | 49 | ||||
-rw-r--r-- | core/vm/jump_table.go | 3 | ||||
-rw-r--r-- | core/vm/opcodes.go | 12 | ||||
-rw-r--r-- | core/vm/runtime/env.go | 4 | ||||
-rw-r--r-- | core/vm/vm.go | 38 |
10 files changed, 94 insertions, 37 deletions
diff --git a/core/vm/contract.go b/core/vm/contract.go index 5981dcca0..dac81a529 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -26,12 +26,14 @@ import ( type ContractRef interface { ReturnGas(*big.Int, *big.Int) Address() common.Address + SetAddress(common.Address) + Value() *big.Int SetCode([]byte) EachStorage(cb func(key, value []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 @@ -45,6 +47,8 @@ type Contract struct { value, Gas, UsedGas, Price *big.Int Args []byte + + DelegateCall bool } // Create a new context for the given data items. @@ -114,6 +118,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 diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 22cb9eab2..f204432a2 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -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 } diff --git a/core/vm/environment.go b/core/vm/environment.go index 4fee583bf..dc60af2ca 100644 --- a/core/vm/environment.go +++ b/core/vm/environment.go @@ -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,7 +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 } diff --git a/core/vm/errors.go b/core/vm/errors.go index e2fc84065..116fbe456 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -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) diff --git a/core/vm/gas.go b/core/vm/gas.go index bff0ac91b..09feddd7d 100644 --- a/core/vm/gas.go +++ b/core/vm/gas.go @@ -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}, diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 2e868521e..9d3d4e6fe 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -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) { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index ab899647f..222c93854 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -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} diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index dc4139092..00593ae95 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -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", diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 22f9ea14d..77519df81 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -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) } diff --git a/core/vm/vm.go b/core/vm/vm.go index 0c6bbcd42..863b2cc0d 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -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()) @@ -346,6 +373,13 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef 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) |