Skip to content

Commit 6140497

Browse files
Gustav Simonssonobscuren
Gustav Simonsson
authored andcommitted
[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
1 parent 300f1e2 commit 6140497

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+23926
-9272
lines changed

cmd/evm/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,15 @@ func (self *VMEnv) Call(caller vm.ContractRef, addr common.Address, data []byte,
225225
self.Gas = gas
226226
return core.Call(self, caller, addr, data, gas, price, value)
227227
}
228+
228229
func (self *VMEnv) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
229230
return core.CallCode(self, caller, addr, data, gas, price, value)
230231
}
231232

233+
func (self *VMEnv) DelegateCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) {
234+
return core.DelegateCall(self, caller, addr, data, gas, price)
235+
}
236+
232237
func (self *VMEnv) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
233238
return core.Create(self, caller, data, gas, price, value)
234239
}

core/bench_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
8282
return func(i int, gen *BlockGen) {
8383
toaddr := common.Address{}
8484
data := make([]byte, nbytes)
85-
gas := IntrinsicGas(data)
85+
gas := IntrinsicGas(data, false, false)
8686
tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey)
8787
gen.AddTx(tx)
8888
}

core/block_validator.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ import (
3030
"gopkg.in/fatih/set.v0"
3131
)
3232

33+
var (
34+
ExpDiffPeriod = big.NewInt(100000)
35+
big10 = big.NewInt(10)
36+
bigMinus99 = big.NewInt(-99)
37+
)
38+
3339
// BlockValidator is responsible for validating block headers, uncles and
3440
// processed state.
3541
//
@@ -111,6 +117,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
111117
// For valid blocks this should always validate to true.
112118
rbloom := types.CreateBloom(receipts)
113119
if rbloom != header.Bloom {
120+
//fmt.Printf("FUNKY: ValidateState: block number: %v\n", block.Number())
114121
return fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
115122
}
116123
// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
@@ -241,3 +248,127 @@ func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, che
241248
}
242249
return nil
243250
}
251+
252+
// CalcDifficulty is the difficulty adjustment algorithm. It returns
253+
// the difficulty that a new block should have when created at time
254+
// given the parent block's time and difficulty.
255+
func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
256+
if params.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
257+
return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
258+
} else {
259+
return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff)
260+
}
261+
}
262+
263+
func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
264+
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki
265+
// algorithm:
266+
// diff = (parent_diff +
267+
// (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
268+
// ) + 2^(periodCount - 2)
269+
270+
bigTime := new(big.Int).SetUint64(time)
271+
bigParentTime := new(big.Int).SetUint64(parentTime)
272+
273+
// for the exponential factor
274+
periodCount := new(big.Int).Add(parentNumber, common.Big1)
275+
periodCount.Div(periodCount, ExpDiffPeriod)
276+
277+
// holds intermediate values to make the algo easier to read & audit
278+
x := new(big.Int)
279+
y := new(big.Int)
280+
281+
// 1 - (block_timestamp -parent_timestamp) // 10
282+
x.Sub(bigTime, bigParentTime)
283+
x.Div(x, big10)
284+
x.Sub(common.Big1, x)
285+
286+
// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
287+
if x.Cmp(bigMinus99) < 0 {
288+
x.Set(bigMinus99)
289+
}
290+
291+
// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
292+
y.Div(parentDiff, params.DifficultyBoundDivisor)
293+
x.Mul(y, x)
294+
x.Add(parentDiff, x)
295+
296+
// minimum difficulty can ever be (before exponential factor)
297+
if x.Cmp(params.MinimumDifficulty) < 0 {
298+
x = params.MinimumDifficulty
299+
}
300+
301+
// the exponential factor, commonly refered to as "the bomb"
302+
// diff = diff + 2^(periodCount - 2)
303+
if periodCount.Cmp(common.Big1) > 0 {
304+
y.Sub(periodCount, common.Big2)
305+
y.Exp(common.Big2, y, nil)
306+
x.Add(x, y)
307+
}
308+
309+
return x
310+
}
311+
312+
func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
313+
diff := new(big.Int)
314+
adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
315+
bigTime := new(big.Int)
316+
bigParentTime := new(big.Int)
317+
318+
bigTime.SetUint64(time)
319+
bigParentTime.SetUint64(parentTime)
320+
321+
if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
322+
diff.Add(parentDiff, adjust)
323+
} else {
324+
diff.Sub(parentDiff, adjust)
325+
}
326+
if diff.Cmp(params.MinimumDifficulty) < 0 {
327+
diff = params.MinimumDifficulty
328+
}
329+
330+
periodCount := new(big.Int).Add(parentNumber, common.Big1)
331+
periodCount.Div(periodCount, ExpDiffPeriod)
332+
if periodCount.Cmp(common.Big1) > 0 {
333+
// diff = diff + 2^(periodCount - 2)
334+
expDiff := periodCount.Sub(periodCount, common.Big2)
335+
expDiff.Exp(common.Big2, expDiff, nil)
336+
diff.Add(diff, expDiff)
337+
diff = common.BigMax(diff, params.MinimumDifficulty)
338+
}
339+
340+
return diff
341+
}
342+
343+
// CalcGasLimit computes the gas limit of the next block after parent.
344+
// The result may be modified by the caller.
345+
// This is miner strategy, not consensus protocol.
346+
func CalcGasLimit(parent *types.Block) *big.Int {
347+
// contrib = (parentGasUsed * 3 / 2) / 1024
348+
contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
349+
contrib = contrib.Div(contrib, big.NewInt(2))
350+
contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
351+
352+
// decay = parentGasLimit / 1024 -1
353+
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
354+
decay.Sub(decay, big.NewInt(1))
355+
356+
/*
357+
strategy: gasLimit of block-to-mine is set based on parent's
358+
gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we
359+
increase it, otherwise lower it (or leave it unchanged if it's right
360+
at that usage) the amount increased/decreased depends on how far away
361+
from parentGasLimit * (2/3) parentGasUsed is.
362+
*/
363+
gl := new(big.Int).Sub(parent.GasLimit(), decay)
364+
gl = gl.Add(gl, contrib)
365+
gl.Set(common.BigMax(gl, params.MinGasLimit))
366+
367+
// however, if we're now below the target (GenesisGasLimit) we increase the
368+
// limit as much as we can (parentGasLimit / 1024 -1)
369+
if gl.Cmp(params.GenesisGasLimit) < 0 {
370+
gl.Add(parent.GasLimit(), decay)
371+
gl.Set(common.BigMin(gl, params.GenesisGasLimit))
372+
}
373+
return gl
374+
}

core/database_util.go

Lines changed: 14 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"github.com/ethereum/go-ethereum/ethdb"
2828
"github.com/ethereum/go-ethereum/logger"
2929
"github.com/ethereum/go-ethereum/logger/glog"
30-
"github.com/ethereum/go-ethereum/params"
3130
"github.com/ethereum/go-ethereum/rlp"
3231
)
3332

@@ -50,77 +49,9 @@ var (
5049
mipmapPre = []byte("mipmap-log-bloom-")
5150
MIPMapLevels = []uint64{1000000, 500000, 100000, 50000, 1000}
5251

53-
ExpDiffPeriod = big.NewInt(100000)
5452
blockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
5553
)
5654

57-
// CalcDifficulty is the difficulty adjustment algorithm. It returns
58-
// the difficulty that a new block b should have when created at time
59-
// given the parent block's time and difficulty.
60-
func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
61-
diff := new(big.Int)
62-
adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
63-
bigTime := new(big.Int)
64-
bigParentTime := new(big.Int)
65-
66-
bigTime.SetUint64(time)
67-
bigParentTime.SetUint64(parentTime)
68-
69-
if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
70-
diff.Add(parentDiff, adjust)
71-
} else {
72-
diff.Sub(parentDiff, adjust)
73-
}
74-
if diff.Cmp(params.MinimumDifficulty) < 0 {
75-
diff = params.MinimumDifficulty
76-
}
77-
78-
periodCount := new(big.Int).Add(parentNumber, common.Big1)
79-
periodCount.Div(periodCount, ExpDiffPeriod)
80-
if periodCount.Cmp(common.Big1) > 0 {
81-
// diff = diff + 2^(periodCount - 2)
82-
expDiff := periodCount.Sub(periodCount, common.Big2)
83-
expDiff.Exp(common.Big2, expDiff, nil)
84-
diff.Add(diff, expDiff)
85-
diff = common.BigMax(diff, params.MinimumDifficulty)
86-
}
87-
88-
return diff
89-
}
90-
91-
// CalcGasLimit computes the gas limit of the next block after parent.
92-
// The result may be modified by the caller.
93-
// This is miner strategy, not consensus protocol.
94-
func CalcGasLimit(parent *types.Block) *big.Int {
95-
// contrib = (parentGasUsed * 3 / 2) / 1024
96-
contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
97-
contrib = contrib.Div(contrib, big.NewInt(2))
98-
contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
99-
100-
// decay = parentGasLimit / 1024 -1
101-
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
102-
decay.Sub(decay, big.NewInt(1))
103-
104-
/*
105-
strategy: gasLimit of block-to-mine is set based on parent's
106-
gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we
107-
increase it, otherwise lower it (or leave it unchanged if it's right
108-
at that usage) the amount increased/decreased depends on how far away
109-
from parentGasLimit * (2/3) parentGasUsed is.
110-
*/
111-
gl := new(big.Int).Sub(parent.GasLimit(), decay)
112-
gl = gl.Add(gl, contrib)
113-
gl.Set(common.BigMax(gl, params.MinGasLimit))
114-
115-
// however, if we're now below the target (GenesisGasLimit) we increase the
116-
// limit as much as we can (parentGasLimit / 1024 -1)
117-
if gl.Cmp(params.GenesisGasLimit) < 0 {
118-
gl.Add(parent.GasLimit(), decay)
119-
gl.Set(common.BigMin(gl, params.GenesisGasLimit))
120-
}
121-
return gl
122-
}
123-
12455
// GetCanonicalHash retrieves a hash assigned to a canonical block number.
12556
func GetCanonicalHash(db ethdb.Database, number uint64) common.Hash {
12657
data, _ := db.Get(append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...))
@@ -164,6 +95,20 @@ func GetHeadFastBlockHash(db ethdb.Database) common.Hash {
16495
return common.BytesToHash(data)
16596
}
16697

98+
// GetHeadBlockNum retrieves the block number of the current canonical head block.
99+
func GetHeadBlockNum(db ethdb.Database) *big.Int {
100+
data, _ := db.Get(headBlockKey)
101+
if len(data) == 0 {
102+
return nil
103+
}
104+
header := new(types.Header)
105+
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
106+
glog.V(logger.Error).Infof("invalid block header RLP for head block: %v", err)
107+
return nil
108+
}
109+
return header.Number
110+
}
111+
167112
// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil
168113
// if the header's not found.
169114
func GetHeaderRLP(db ethdb.Database, hash common.Hash) rlp.RawValue {

core/execution.go

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,18 @@ func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input
3333

3434
// CallCode executes the given address' code as the given contract address
3535
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
36-
prev := caller.Address()
37-
ret, _, err = exec(env, caller, &prev, &addr, input, env.Db().GetCode(addr), gas, gasPrice, value)
36+
callerAddr := caller.Address()
37+
ret, _, err = exec(env, caller, &callerAddr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, value)
38+
return ret, err
39+
}
40+
41+
// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
42+
func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
43+
callerAddr := caller.Address()
44+
originAddr := env.Origin()
45+
callerValue := caller.Value()
46+
ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, callerValue)
47+
caller.SetAddress(callerAddr)
3848
return ret, err
3949
}
4050

@@ -52,7 +62,6 @@ func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPric
5262

5363
func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
5464
evm := vm.NewVm(env)
55-
5665
// Depth check execution. Fail if we're trying to execute above the
5766
// limit.
5867
if env.Depth() > int(params.CallCreateDepth.Int64()) {
@@ -72,13 +81,11 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
7281
// Generate a new address
7382
nonce := env.Db().GetNonce(caller.Address())
7483
env.Db().SetNonce(caller.Address(), nonce+1)
75-
7684
addr = crypto.CreateAddress(caller.Address(), nonce)
77-
7885
address = &addr
7986
createAccount = true
8087
}
81-
snapshot := env.MakeSnapshot()
88+
snapshotPreTransfer := env.MakeSnapshot()
8289

8390
var (
8491
from = env.Db().GetAccount(caller.Address())
@@ -94,15 +101,62 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
94101
}
95102
}
96103
env.Transfer(from, to, value)
104+
snapshotPostTransfer := env.MakeSnapshot()
97105

98106
contract := vm.NewContract(caller, to, value, gas, gasPrice)
99107
contract.SetCallCode(codeAddr, code)
100108

101109
ret, err = evm.Run(contract, input)
110+
102111
if err != nil {
103-
env.SetSnapshot(snapshot) //env.Db().Set(snapshot)
112+
if err == vm.CodeStoreOutOfGasError {
113+
// TODO: this is rather hacky, restore all state changes
114+
// except sender's account nonce increment
115+
toNonce := env.Db().GetNonce(to.Address())
116+
env.SetSnapshot(snapshotPostTransfer)
117+
env.Db().SetNonce(to.Address(), toNonce)
118+
} else {
119+
env.SetSnapshot(snapshotPreTransfer) //env.Db().Set(snapshot)
120+
}
121+
}
122+
return ret, addr, err
123+
}
124+
125+
func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
126+
evm := vm.NewVm(env)
127+
// Depth check execution. Fail if we're trying to execute above the
128+
// limit.
129+
if env.Depth() > int(params.CallCreateDepth.Int64()) {
130+
caller.ReturnGas(gas, gasPrice)
131+
return nil, common.Address{}, vm.DepthError
132+
}
133+
134+
if !env.CanTransfer(*originAddr, value) {
135+
caller.ReturnGas(gas, gasPrice)
136+
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
137+
}
138+
139+
snapshot := env.MakeSnapshot()
140+
141+
var (
142+
//from = env.Db().GetAccount(*originAddr)
143+
to vm.Account
144+
)
145+
if !env.Db().Exist(*toAddr) {
146+
to = env.Db().CreateAccount(*toAddr)
147+
} else {
148+
to = env.Db().GetAccount(*toAddr)
104149
}
105150

151+
contract := vm.NewContract(caller, to, value, gas, gasPrice)
152+
contract.SetCallCode(codeAddr, code)
153+
contract.DelegateCall = true
154+
155+
ret, err = evm.Run(contract, input)
156+
157+
if err != nil {
158+
env.SetSnapshot(snapshot) //env.Db().Set(snapshot)
159+
}
106160
return ret, addr, err
107161
}
108162

0 commit comments

Comments
 (0)