Commit 371871d6 authored by Gustav Simonsson's avatar Gustav Simonsson Committed by Jeffrey Wilcke

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
parent aa36a6ae
...@@ -225,10 +225,15 @@ func (self *VMEnv) Call(caller vm.ContractRef, addr common.Address, data []byte, ...@@ -225,10 +225,15 @@ func (self *VMEnv) Call(caller vm.ContractRef, addr common.Address, data []byte,
self.Gas = gas self.Gas = gas
return core.Call(self, caller, addr, data, gas, price, value) return core.Call(self, caller, addr, data, gas, price, value)
} }
func (self *VMEnv) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { func (self *VMEnv) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
return core.CallCode(self, caller, addr, data, gas, price, value) return core.CallCode(self, caller, addr, data, gas, price, value)
} }
func (self *VMEnv) DelegateCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) {
return core.DelegateCall(self, caller, addr, data, gas, price)
}
func (self *VMEnv) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { func (self *VMEnv) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
return core.Create(self, caller, data, gas, price, value) return core.Create(self, caller, data, gas, price, value)
} }
...@@ -82,7 +82,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { ...@@ -82,7 +82,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) { return func(i int, gen *BlockGen) {
toaddr := common.Address{} toaddr := common.Address{}
data := make([]byte, nbytes) data := make([]byte, nbytes)
gas := IntrinsicGas(data) gas := IntrinsicGas(data, false, false)
tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey) tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey)
gen.AddTx(tx) gen.AddTx(tx)
} }
......
...@@ -30,6 +30,12 @@ import ( ...@@ -30,6 +30,12 @@ import (
"gopkg.in/fatih/set.v0" "gopkg.in/fatih/set.v0"
) )
var (
ExpDiffPeriod = big.NewInt(100000)
big10 = big.NewInt(10)
bigMinus99 = big.NewInt(-99)
)
// BlockValidator is responsible for validating block headers, uncles and // BlockValidator is responsible for validating block headers, uncles and
// processed state. // processed state.
// //
...@@ -111,6 +117,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat ...@@ -111,6 +117,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
// For valid blocks this should always validate to true. // For valid blocks this should always validate to true.
rbloom := types.CreateBloom(receipts) rbloom := types.CreateBloom(receipts)
if rbloom != header.Bloom { if rbloom != header.Bloom {
//fmt.Printf("FUNKY: ValidateState: block number: %v\n", block.Number())
return fmt.Errorf("unable to replicate block's bloom=%x", rbloom) return fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
} }
// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) // 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 ...@@ -241,3 +248,127 @@ func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, che
} }
return nil return nil
} }
// CalcDifficulty is the difficulty adjustment algorithm. It returns
// the difficulty that a new block should have when created at time
// given the parent block's time and difficulty.
func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
if params.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
} else {
return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff)
}
}
func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki
// algorithm:
// diff = (parent_diff +
// (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
// ) + 2^(periodCount - 2)
bigTime := new(big.Int).SetUint64(time)
bigParentTime := new(big.Int).SetUint64(parentTime)
// for the exponential factor
periodCount := new(big.Int).Add(parentNumber, common.Big1)
periodCount.Div(periodCount, ExpDiffPeriod)
// holds intermediate values to make the algo easier to read & audit
x := new(big.Int)
y := new(big.Int)
// 1 - (block_timestamp -parent_timestamp) // 10
x.Sub(bigTime, bigParentTime)
x.Div(x, big10)
x.Sub(common.Big1, x)
// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
if x.Cmp(bigMinus99) < 0 {
x.Set(bigMinus99)
}
// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
y.Div(parentDiff, params.DifficultyBoundDivisor)
x.Mul(y, x)
x.Add(parentDiff, x)
// minimum difficulty can ever be (before exponential factor)
if x.Cmp(params.MinimumDifficulty) < 0 {
x = params.MinimumDifficulty
}
// the exponential factor, commonly refered to as "the bomb"
// diff = diff + 2^(periodCount - 2)
if periodCount.Cmp(common.Big1) > 0 {
y.Sub(periodCount, common.Big2)
y.Exp(common.Big2, y, nil)
x.Add(x, y)
}
return x
}
func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
diff := new(big.Int)
adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
bigTime := new(big.Int)
bigParentTime := new(big.Int)
bigTime.SetUint64(time)
bigParentTime.SetUint64(parentTime)
if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
diff.Add(parentDiff, adjust)
} else {
diff.Sub(parentDiff, adjust)
}
if diff.Cmp(params.MinimumDifficulty) < 0 {
diff = params.MinimumDifficulty
}
periodCount := new(big.Int).Add(parentNumber, common.Big1)
periodCount.Div(periodCount, ExpDiffPeriod)
if periodCount.Cmp(common.Big1) > 0 {
// diff = diff + 2^(periodCount - 2)
expDiff := periodCount.Sub(periodCount, common.Big2)
expDiff.Exp(common.Big2, expDiff, nil)
diff.Add(diff, expDiff)
diff = common.BigMax(diff, params.MinimumDifficulty)
}
return diff
}
// CalcGasLimit computes the gas limit of the next block after parent.
// The result may be modified by the caller.
// This is miner strategy, not consensus protocol.
func CalcGasLimit(parent *types.Block) *big.Int {
// contrib = (parentGasUsed * 3 / 2) / 1024
contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
contrib = contrib.Div(contrib, big.NewInt(2))
contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
// decay = parentGasLimit / 1024 -1
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
decay.Sub(decay, big.NewInt(1))
/*
strategy: gasLimit of block-to-mine is set based on parent's
gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we
increase it, otherwise lower it (or leave it unchanged if it's right
at that usage) the amount increased/decreased depends on how far away
from parentGasLimit * (2/3) parentGasUsed is.
*/
gl := new(big.Int).Sub(parent.GasLimit(), decay)
gl = gl.Add(gl, contrib)
gl.Set(common.BigMax(gl, params.MinGasLimit))
// however, if we're now below the target (GenesisGasLimit) we increase the
// limit as much as we can (parentGasLimit / 1024 -1)
if gl.Cmp(params.GenesisGasLimit) < 0 {
gl.Add(parent.GasLimit(), decay)
gl.Set(common.BigMin(gl, params.GenesisGasLimit))
}
return gl
}
...@@ -27,7 +27,6 @@ import ( ...@@ -27,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
...@@ -50,77 +49,9 @@ var ( ...@@ -50,77 +49,9 @@ var (
mipmapPre = []byte("mipmap-log-bloom-") mipmapPre = []byte("mipmap-log-bloom-")
MIPMapLevels = []uint64{1000000, 500000, 100000, 50000, 1000} MIPMapLevels = []uint64{1000000, 500000, 100000, 50000, 1000}
ExpDiffPeriod = big.NewInt(100000)
blockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually] blockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
) )
// CalcDifficulty is the difficulty adjustment algorithm. It returns
// the difficulty that a new block b should have when created at time
// given the parent block's time and difficulty.
func CalcDifficulty(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
diff := new(big.Int)
adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
bigTime := new(big.Int)
bigParentTime := new(big.Int)
bigTime.SetUint64(time)
bigParentTime.SetUint64(parentTime)
if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
diff.Add(parentDiff, adjust)
} else {
diff.Sub(parentDiff, adjust)
}
if diff.Cmp(params.MinimumDifficulty) < 0 {
diff = params.MinimumDifficulty
}
periodCount := new(big.Int).Add(parentNumber, common.Big1)
periodCount.Div(periodCount, ExpDiffPeriod)
if periodCount.Cmp(common.Big1) > 0 {
// diff = diff + 2^(periodCount - 2)
expDiff := periodCount.Sub(periodCount, common.Big2)
expDiff.Exp(common.Big2, expDiff, nil)
diff.Add(diff, expDiff)
diff = common.BigMax(diff, params.MinimumDifficulty)
}
return diff
}
// CalcGasLimit computes the gas limit of the next block after parent.
// The result may be modified by the caller.
// This is miner strategy, not consensus protocol.
func CalcGasLimit(parent *types.Block) *big.Int {
// contrib = (parentGasUsed * 3 / 2) / 1024
contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
contrib = contrib.Div(contrib, big.NewInt(2))
contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
// decay = parentGasLimit / 1024 -1
decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
decay.Sub(decay, big.NewInt(1))
/*
strategy: gasLimit of block-to-mine is set based on parent's
gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we
increase it, otherwise lower it (or leave it unchanged if it's right
at that usage) the amount increased/decreased depends on how far away
from parentGasLimit * (2/3) parentGasUsed is.
*/
gl := new(big.Int).Sub(parent.GasLimit(), decay)
gl = gl.Add(gl, contrib)
gl.Set(common.BigMax(gl, params.MinGasLimit))
// however, if we're now below the target (GenesisGasLimit) we increase the
// limit as much as we can (parentGasLimit / 1024 -1)
if gl.Cmp(params.GenesisGasLimit) < 0 {
gl.Add(parent.GasLimit(), decay)
gl.Set(common.BigMin(gl, params.GenesisGasLimit))
}
return gl
}
// GetCanonicalHash retrieves a hash assigned to a canonical block number. // GetCanonicalHash retrieves a hash assigned to a canonical block number.
func GetCanonicalHash(db ethdb.Database, number uint64) common.Hash { func GetCanonicalHash(db ethdb.Database, number uint64) common.Hash {
data, _ := db.Get(append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...)) data, _ := db.Get(append(blockNumPrefix, big.NewInt(int64(number)).Bytes()...))
...@@ -164,6 +95,20 @@ func GetHeadFastBlockHash(db ethdb.Database) common.Hash { ...@@ -164,6 +95,20 @@ func GetHeadFastBlockHash(db ethdb.Database) common.Hash {
return common.BytesToHash(data) return common.BytesToHash(data)
} }
// GetHeadBlockNum retrieves the block number of the current canonical head block.
func GetHeadBlockNum(db ethdb.Database) *big.Int {
data, _ := db.Get(headBlockKey)
if len(data) == 0 {
return nil
}
header := new(types.Header)
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
glog.V(logger.Error).Infof("invalid block header RLP for head block: %v", err)
return nil
}
return header.Number
}
// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil // GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil
// if the header's not found. // if the header's not found.
func GetHeaderRLP(db ethdb.Database, hash common.Hash) rlp.RawValue { func GetHeaderRLP(db ethdb.Database, hash common.Hash) rlp.RawValue {
......
...@@ -33,8 +33,18 @@ func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input ...@@ -33,8 +33,18 @@ func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input
// CallCode executes the given address' code as the given contract address // CallCode executes the given address' code as the given contract address
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
prev := caller.Address() callerAddr := caller.Address()
ret, _, err = exec(env, caller, &prev, &addr, input, env.Db().GetCode(addr), gas, gasPrice, value) ret, _, err = exec(env, caller, &callerAddr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, value)
return ret, err
}
// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
callerAddr := caller.Address()
originAddr := env.Origin()
callerValue := caller.Value()
ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, input, env.Db().GetCode(addr), gas, gasPrice, callerValue)
caller.SetAddress(callerAddr)
return ret, err return ret, err
} }
...@@ -52,7 +62,6 @@ func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPric ...@@ -52,7 +62,6 @@ func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPric
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) { 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) {
evm := vm.NewVm(env) evm := vm.NewVm(env)
// Depth check execution. Fail if we're trying to execute above the // Depth check execution. Fail if we're trying to execute above the
// limit. // limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) { if env.Depth() > int(params.CallCreateDepth.Int64()) {
...@@ -72,13 +81,11 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A ...@@ -72,13 +81,11 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
// Generate a new address // Generate a new address
nonce := env.Db().GetNonce(caller.Address()) nonce := env.Db().GetNonce(caller.Address())
env.Db().SetNonce(caller.Address(), nonce+1) env.Db().SetNonce(caller.Address(), nonce+1)
addr = crypto.CreateAddress(caller.Address(), nonce) addr = crypto.CreateAddress(caller.Address(), nonce)
address = &addr address = &addr
createAccount = true createAccount = true
} }
snapshot := env.MakeSnapshot() snapshotPreTransfer := env.MakeSnapshot()
var ( var (
from = env.Db().GetAccount(caller.Address()) from = env.Db().GetAccount(caller.Address())
...@@ -94,15 +101,62 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A ...@@ -94,15 +101,62 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
} }
} }
env.Transfer(from, to, value) env.Transfer(from, to, value)
snapshotPostTransfer := env.MakeSnapshot()
contract := vm.NewContract(caller, to, value, gas, gasPrice) contract := vm.NewContract(caller, to, value, gas, gasPrice)
contract.SetCallCode(codeAddr, code) contract.SetCallCode(codeAddr, code)
ret, err = evm.Run(contract, input) ret, err = evm.Run(contract, input)
if err != nil { if err != nil {
env.SetSnapshot(snapshot) //env.Db().Set(snapshot) if err == vm.CodeStoreOutOfGasError {
// TODO: this is rather hacky, restore all state changes
// except sender's account nonce increment
toNonce := env.Db().GetNonce(to.Address())
env.SetSnapshot(snapshotPostTransfer)
env.Db().SetNonce(to.Address(), toNonce)
} else {
env.SetSnapshot(snapshotPreTransfer) //env.Db().Set(snapshot)
}
}
return ret, addr, err
}
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) {
evm := vm.NewVm(env)
// Depth check execution. Fail if we're trying to execute above the
// limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, vm.DepthError
}
if !env.CanTransfer(*originAddr, value) {
caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
}
snapshot := env.MakeSnapshot()
var (
//from = env.Db().GetAccount(*originAddr)
to vm.Account
)
if !env.Db().Exist(*toAddr) {
to = env.Db().CreateAccount(*toAddr)
} else {
to = env.Db().GetAccount(*toAddr)
} }
contract := vm.NewContract(caller, to, value, gas, gasPrice)
contract.SetCallCode(codeAddr, code)
contract.DelegateCall = true
ret, err = evm.Run(contract, input)
if err != nil {
env.SetSnapshot(snapshot) //env.Db().Set(snapshot)
}
return ret, addr, err return ret, addr, err
} }
......
...@@ -211,6 +211,11 @@ func (c *StateObject) Address() common.Address { ...@@ -211,6 +211,11 @@ func (c *StateObject) Address() common.Address {
return c.address return c.address
} }
// Sets the address of the contract/account
func (c *StateObject) SetAddress(addr common.Address) {
c.address = addr
}
func (self *StateObject) Trie() *trie.SecureTrie { func (self *StateObject) Trie() *trie.SecureTrie {
return self.trie return self.trie
} }
...@@ -238,6 +243,13 @@ func (self *StateObject) Nonce() uint64 { ...@@ -238,6 +243,13 @@ func (self *StateObject) Nonce() uint64 {
return self.nonce return self.nonce
} }
// Never called, but must be present to allow StateObject to be used
// as a vm.Account interface that also satisfies the vm.ContractRef
// interface. Interfaces are awesome.
func (self *StateObject) Value() *big.Int {
return nil
}
func (self *StateObject) EachStorage(cb func(key, value []byte)) { func (self *StateObject) EachStorage(cb func(key, value []byte)) {
// When iterating over the storage check the cache first // When iterating over the storage check the cache first
for h, v := range self.storage { for h, v := range self.storage {
......
...@@ -87,6 +87,18 @@ func (self *StateDB) GetLogs(hash common.Hash) vm.Logs { ...@@ -87,6 +87,18 @@ func (self *StateDB) GetLogs(hash common.Hash) vm.Logs {
return self.logs[hash] return self.logs[hash]
} }
func (self *StateDB) GetAllLogs() *map[common.Hash]vm.Logs {
copy := make(map[common.Hash]vm.Logs, len(self.logs))
for k, v := range self.logs {
copy[k] = v
}
return &copy
}
func (self *StateDB) SetAllLogs(logs *map[common.Hash]vm.Logs) {
self.logs = *logs
}
func (self *StateDB) Logs() vm.Logs { func (self *StateDB) Logs() vm.Logs {
var logs vm.Logs var logs vm.Logs
for _, lgs := range self.logs { for _, lgs := range self.logs {
...@@ -95,6 +107,11 @@ func (self *StateDB) Logs() vm.Logs { ...@@ -95,6 +107,11 @@ func (self *StateDB) Logs() vm.Logs {
return logs return logs
} }
// TODO: this may not be the most proper thing
func (self *StateDB) GetDB() ethdb.Database {
return self.db
}
func (self *StateDB) AddRefund(gas *big.Int) { func (self *StateDB) AddRefund(gas *big.Int) {
self.refund.Add(self.refund, gas) self.refund.Add(self.refund, gas)
} }
......
...@@ -43,7 +43,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB) (ty ...@@ -43,7 +43,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB) (ty
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
statedb.StartRecord(tx.Hash(), block.Hash(), i) statedb.StartRecord(tx.Hash(), block.Hash(), i)
receipt, logs, _, err := ApplyTransaction(p.bc, gp, statedb, header, tx, totalUsedGas) receipt, logs, _, err := ApplyTransaction(p.bc, gp, statedb, header, tx, totalUsedGas)
if err != nil { if err != nil {
return nil, nil, totalUsedGas, err return nil, nil, totalUsedGas, err
......
...@@ -21,12 +21,17 @@ import ( ...@@ -21,12 +21,17 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
var (
Big0 = big.NewInt(0)
)
/* /*
The State Transitioning Model The State Transitioning Model
...@@ -59,6 +64,7 @@ type StateTransition struct { ...@@ -59,6 +64,7 @@ type StateTransition struct {
// Message represents a message sent to a contract. // Message represents a message sent to a contract.
type Message interface { type Message interface {
From() (common.Address, error) From() (common.Address, error)
FromFrontier() (common.Address, error)
To() *common.Address To() *common.Address
GasPrice() *big.Int GasPrice() *big.Int
...@@ -75,8 +81,13 @@ func MessageCreatesContract(msg Message) bool { ...@@ -75,8 +81,13 @@ func MessageCreatesContract(msg Message) bool {
// IntrinsicGas computes the 'intrisic gas' for a message // IntrinsicGas computes the 'intrisic gas' for a message
// with the given data. // with the given data.
func IntrinsicGas(data []byte) *big.Int { func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
igas := new(big.Int).Set(params.TxGas) igas := new(big.Int)
if contractCreation && homestead {
igas.Set(params.TxGasContractCreation)
} else {
igas.Set(params.TxGas)
}
if len(data) > 0 { if len(data) > 0 {
var nz int64 var nz int64
for _, byt := range data { for _, byt := range data {
...@@ -110,7 +121,15 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In ...@@ -110,7 +121,15 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In
} }
func (self *StateTransition) from() (vm.Account, error) { func (self *StateTransition) from() (vm.Account, error) {
f, err := self.msg.From() var (
f common.Address
err error
)
if params.IsHomestead(self.env.BlockNumber()) {
f, err = self.msg.From()
} else {
f, err = self.msg.FromFrontier()
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -195,18 +214,20 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e ...@@ -195,18 +214,20 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e
if err = self.preCheck(); err != nil { if err = self.preCheck(); err != nil {
return return
} }
msg := self.msg msg := self.msg
sender, _ := self.from() // err checked in preCheck sender, _ := self.from() // err checked in preCheck
homestead := params.IsHomestead(self.env.BlockNumber())
contractCreation := MessageCreatesContract(msg)
// Pay intrinsic gas // Pay intrinsic gas
if err = self.useGas(IntrinsicGas(self.data)); err != nil { if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
return nil, nil, InvalidTxError(err) return nil, nil, InvalidTxError(err)
} }
vmenv := self.env vmenv := self.env
snapshot := vmenv.MakeSnapshot()
var addr common.Address var addr common.Address
if MessageCreatesContract(msg) { if contractCreation {
ret, addr, err = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value) ret, addr, err = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value)
if err == nil { if err == nil {
dataGas := big.NewInt(int64(len(ret))) dataGas := big.NewInt(int64(len(ret)))
...@@ -214,6 +235,18 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e ...@@ -214,6 +235,18 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e
if err := self.useGas(dataGas); err == nil { if err := self.useGas(dataGas); err == nil {
self.state.SetCode(addr, ret) self.state.SetCode(addr, ret)
} else { } else {
if homestead {
// rollback all contract creation changes except for
// sender's incremented account nonce and gas usage
// TODO: fucking gas hack... verify potential DoS vuln
accNonce := vmenv.Db().GetNonce(sender.Address())
logs := vmenv.Db().(*state.StateDB).GetAllLogs()
vmenv.SetSnapshot(snapshot)
vmenv.Db().SetNonce(sender.Address(), accNonce)
vmenv.Db().(*state.StateDB).SetAllLogs(logs)
self.gas = Big0
}
ret = nil // does not affect consensus but useful for StateTests validations ret = nil // does not affect consensus but useful for StateTests validations
glog.V(logger.Core).Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas) glog.V(logger.Core).Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas)
} }
......
...@@ -30,6 +30,7 @@ import ( ...@@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
) )
var ( var (
...@@ -222,18 +223,26 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { ...@@ -222,18 +223,26 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
return ErrCheap return ErrCheap
} }
currentState, err := pool.currentState()
if err != nil {
return err
}
homestead := params.IsHomestead(GetHeadBlockNum(currentState.GetDB()))
// Validate the transaction sender and it's sig. Throw // Validate the transaction sender and it's sig. Throw
// if the from fields is invalid. // if the from fields is invalid.
if from, err = tx.From(); err != nil { if homestead {
from, err = tx.From()
} else {
from, err = tx.FromFrontier()
}
if err != nil {
return ErrInvalidSender return ErrInvalidSender
} }
// Make sure the account exist. Non existent accounts // Make sure the account exist. Non existent accounts
// haven't got funds and well therefor never pass. // haven't got funds and well therefor never pass.
currentState, err := pool.currentState()
if err != nil {
return err
}
if !currentState.HasAccount(from) { if !currentState.HasAccount(from) {
return ErrNonExistentAccount return ErrNonExistentAccount
} }
...@@ -263,7 +272,8 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { ...@@ -263,7 +272,8 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
} }
// Should supply enough intrinsic gas // Should supply enough intrinsic gas
if tx.Gas().Cmp(IntrinsicGas(tx.Data())) < 0 { intrGas := IntrinsicGas(tx.Data(), MessageCreatesContract(tx), homestead)
if tx.Gas().Cmp(intrGas) < 0 {
return ErrIntrinsicGas return ErrIntrinsicGas
} }
......
...@@ -157,11 +157,26 @@ func (tx *Transaction) Size() common.StorageSize { ...@@ -157,11 +157,26 @@ func (tx *Transaction) Size() common.StorageSize {
return common.StorageSize(c) return common.StorageSize(c)
} }
// From() caches the address, allowing it to be used regardless of
// Frontier / Homestead. however, the first time called it runs
// signature validations, so we need two versions. This makes it
// easier to ensure backwards compatibility of things like package rpc
// where eth_getblockbynumber uses tx.From() and needs to work for
// both txs before and after the first homestead block. Signatures
// valid in homestead are a subset of valid ones in Frontier)
func (tx *Transaction) From() (common.Address, error) { func (tx *Transaction) From() (common.Address, error) {
return doFrom(tx, true)
}
func (tx *Transaction) FromFrontier() (common.Address, error) {
return doFrom(tx, false)
}
func doFrom(tx *Transaction, homestead bool) (common.Address, error) {
if from := tx.from.Load(); from != nil { if from := tx.from.Load(); from != nil {
return from.(common.Address), nil return from.(common.Address), nil
} }
pubkey, err := tx.publicKey() pubkey, err := tx.publicKey(homestead)
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
...@@ -182,8 +197,8 @@ func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int) { ...@@ -182,8 +197,8 @@ func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int) {
return tx.data.V, new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S) return tx.data.V, new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S)
} }
func (tx *Transaction) publicKey() ([]byte, error) { func (tx *Transaction) publicKey(homestead bool) ([]byte, error) {
if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S) { if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S, homestead) {
return nil, ErrInvalidSig return nil, ErrInvalidSig
} }
......
...@@ -26,12 +26,14 @@ import ( ...@@ -26,12 +26,14 @@ import (
type ContractRef interface { type ContractRef interface {
ReturnGas(*big.Int, *big.Int) ReturnGas(*big.Int, *big.Int)
Address() common.Address Address() common.Address
SetAddress(common.Address)
Value() *big.Int
SetCode([]byte) SetCode([]byte)
EachStorage(cb func(key, value []byte)) EachStorage(cb func(key, value []byte))
} }
// Contract represents an ethereum contract in the state database. It contains // 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 { type Contract struct {
caller ContractRef caller ContractRef
self ContractRef self ContractRef
...@@ -45,6 +47,8 @@ type Contract struct { ...@@ -45,6 +47,8 @@ type Contract struct {
value, Gas, UsedGas, Price *big.Int value, Gas, UsedGas, Price *big.Int
Args []byte Args []byte
DelegateCall bool
} }
// Create a new context for the given data items. // Create a new context for the given data items.
...@@ -114,6 +118,16 @@ func (c *Contract) Address() common.Address { ...@@ -114,6 +118,16 @@ func (c *Contract) Address() common.Address {
return c.self.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 // SetCode sets the code to the contract
func (self *Contract) SetCode(code []byte) { func (self *Contract) SetCode(code []byte) {
self.Code = code self.Code = code
......
...@@ -93,7 +93,8 @@ func ecrecoverFunc(in []byte) []byte { ...@@ -93,7 +93,8 @@ func ecrecoverFunc(in []byte) []byte {
vbig := common.Bytes2Big(in[32:64]) vbig := common.Bytes2Big(in[32:64])
v := byte(vbig.Uint64()) 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") glog.V(logger.Debug).Infof("EC RECOVER FAIL: v, r or s value invalid")
return nil return nil
} }
......
...@@ -70,6 +70,8 @@ type Environment interface { ...@@ -70,6 +70,8 @@ type Environment interface {
Call(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) 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 // 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) 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 a new contract
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
} }
...@@ -119,7 +121,9 @@ type Account interface { ...@@ -119,7 +121,9 @@ type Account interface {
SetNonce(uint64) SetNonce(uint64)
Balance() *big.Int Balance() *big.Int
Address() common.Address Address() common.Address
SetAddress(common.Address)
ReturnGas(*big.Int, *big.Int) ReturnGas(*big.Int, *big.Int)
SetCode([]byte) SetCode([]byte)
EachStorage(cb func(key, value []byte)) EachStorage(cb func(key, value []byte))
Value() *big.Int
} }
...@@ -24,4 +24,5 @@ import ( ...@@ -24,4 +24,5 @@ import (
) )
var OutOfGasError = errors.New("Out of gas") 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) var DepthError = fmt.Errorf("Max call depth exceeded (%d)", params.CallCreateDepth)
...@@ -136,6 +136,7 @@ var _baseCheck = map[OpCode]req{ ...@@ -136,6 +136,7 @@ var _baseCheck = map[OpCode]req{
CREATE: {3, params.CreateGas, 1}, CREATE: {3, params.CreateGas, 1},
CALL: {7, params.CallGas, 1}, CALL: {7, params.CallGas, 1},
CALLCODE: {7, params.CallGas, 1}, CALLCODE: {7, params.CallGas, 1},
DELEGATECALL: {6, params.CallGas, 1},
JUMPDEST: {0, params.JumpdestGas, 0}, JUMPDEST: {0, params.JumpdestGas, 0},
SUICIDE: {1, Zero, 0}, SUICIDE: {1, Zero, 0},
RETURN: {2, Zero, 0}, RETURN: {2, Zero, 0},
......
...@@ -337,7 +337,13 @@ func opOrigin(instr instruction, pc *uint64, env Environment, contract *Contract ...@@ -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) { 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) { 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, ...@@ -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) { func opSstore(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
loc := common.BigToHash(stack.pop()) loc := common.BigToHash(stack.pop())
val := stack.pop() val := stack.pop()
env.Db().SetState(contract.Address(), loc, common.BigToHash(val)) env.Db().SetState(contract.Address(), loc, common.BigToHash(val))
} }
...@@ -509,31 +514,6 @@ func opGas(instr instruction, pc *uint64, env Environment, contract *Contract, m ...@@ -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) { 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) { 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 ...@@ -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 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) { func opStop(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
......
...@@ -62,9 +62,10 @@ func init() { ...@@ -62,9 +62,10 @@ func init() {
jumpTable[PC] = jumpPtr{nil, true} jumpTable[PC] = jumpPtr{nil, true}
jumpTable[MSIZE] = jumpPtr{opMsize, true} jumpTable[MSIZE] = jumpPtr{opMsize, true}
jumpTable[GAS] = jumpPtr{opGas, true} jumpTable[GAS] = jumpPtr{opGas, true}
jumpTable[CREATE] = jumpPtr{opCreate, true} jumpTable[CREATE] = jumpPtr{nil, true}
jumpTable[CALL] = jumpPtr{opCall, true} jumpTable[CALL] = jumpPtr{opCall, true}
jumpTable[CALLCODE] = jumpPtr{opCallCode, true} jumpTable[CALLCODE] = jumpPtr{opCallCode, true}
jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true}
jumpTable[LOG0] = jumpPtr{makeLog(0), true} jumpTable[LOG0] = jumpPtr{makeLog(0), true}
jumpTable[LOG1] = jumpPtr{makeLog(1), true} jumpTable[LOG1] = jumpPtr{makeLog(1), true}
jumpTable[LOG2] = jumpPtr{makeLog(2), true} jumpTable[LOG2] = jumpPtr{makeLog(2), true}
......
...@@ -200,6 +200,7 @@ const ( ...@@ -200,6 +200,7 @@ const (
CALL CALL
CALLCODE CALLCODE
RETURN RETURN
DELEGATECALL
SUICIDE = 0xff SUICIDE = 0xff
) )
...@@ -349,11 +350,12 @@ var opCodeToString = map[OpCode]string{ ...@@ -349,11 +350,12 @@ var opCodeToString = map[OpCode]string{
LOG4: "LOG4", LOG4: "LOG4",
// 0xf0 range // 0xf0 range
CREATE: "CREATE", CREATE: "CREATE",
CALL: "CALL", CALL: "CALL",
RETURN: "RETURN", RETURN: "RETURN",
CALLCODE: "CALLCODE", CALLCODE: "CALLCODE",
SUICIDE: "SUICIDE", DELEGATECALL: "DELEGATECALL",
SUICIDE: "SUICIDE",
PUSH: "PUSH", PUSH: "PUSH",
DUP: "DUP", DUP: "DUP",
......
...@@ -101,6 +101,10 @@ func (self *Env) CallCode(caller vm.ContractRef, addr common.Address, data []byt ...@@ -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) 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) { 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) return core.Create(self, caller, data, gas, price, value)
} }
...@@ -160,7 +160,6 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) { ...@@ -160,7 +160,6 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) {
// Get the memory location of pc // Get the memory location of pc
op = contract.GetOp(pc) op = contract.GetOp(pc)
// calculate the new memory size and gas price for the current executing opcode // 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) newMemSize, cost, err = calculateGasAndSize(self.env, contract, caller, op, statedb, mem, stack)
if err != nil { if err != nil {
...@@ -177,7 +176,6 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) { ...@@ -177,7 +176,6 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) {
mem.Resize(newMemSize.Uint64()) mem.Resize(newMemSize.Uint64())
// Add a log message // Add a log message
self.log(pc, op, contract.Gas, cost, mem, stack, contract, nil) self.log(pc, op, contract.Gas, cost, mem, stack, contract, nil)
if opPtr := jumpTable[op]; opPtr.valid { if opPtr := jumpTable[op]; opPtr.valid {
if opPtr.fn != nil { if opPtr.fn != nil {
opPtr.fn(instruction{}, &pc, self.env, contract, mem, stack) 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) { ...@@ -201,6 +199,35 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) {
continue 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: case RETURN:
offset, size := stack.pop(), stack.pop() offset, size := stack.pop(), stack.pop()
ret := mem.GetPtr(offset.Int64(), size.Int64()) ret := mem.GetPtr(offset.Int64(), size.Int64())
...@@ -345,6 +372,13 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef ...@@ -345,6 +372,13 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
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 = 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) newMemSize = common.BigMax(x, y)
} }
quadMemGas(mem, newMemSize, gas) quadMemGas(mem, newMemSize, gas)
......
...@@ -106,6 +106,10 @@ func (self *VMEnv) CallCode(me vm.ContractRef, addr common.Address, data []byte, ...@@ -106,6 +106,10 @@ func (self *VMEnv) CallCode(me vm.ContractRef, addr common.Address, data []byte,
return CallCode(self, me, addr, data, gas, price, value) return CallCode(self, me, addr, data, gas, price, value)
} }
func (self *VMEnv) DelegateCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) {
return DelegateCall(self, me, addr, data, gas, price)
}
func (self *VMEnv) Create(me vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { func (self *VMEnv) Create(me vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
return Create(self, me, data, gas, price, value) return Create(self, me, data, gas, price, value)
} }
......
...@@ -163,12 +163,21 @@ func GenerateKey() (*ecdsa.PrivateKey, error) { ...@@ -163,12 +163,21 @@ func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
} }
func ValidateSignatureValues(v byte, r, s *big.Int) bool { func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
if r.Cmp(common.Big1) < 0 || s.Cmp(common.Big1) < 0 { if r.Cmp(common.Big1) < 0 || s.Cmp(common.Big1) < 0 {
return false return false
} }
vint := uint32(v) vint := uint32(v)
if r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) { // reject upper range of s values (ECDSA malleability)
// see discussion in secp256k1/libsecp256k1/include/secp256k1.h
if homestead && s.Cmp(secp256k1.HalfN) > 0 {
return false
}
// Frontier: allow s to be in full N range
if s.Cmp(secp256k1.N) >= 0 {
return false
}
if r.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) {
return true return true
} else { } else {
return false return false
......
...@@ -174,7 +174,7 @@ func TestLoadECDSAFile(t *testing.T) { ...@@ -174,7 +174,7 @@ func TestLoadECDSAFile(t *testing.T) {
func TestValidateSignatureValues(t *testing.T) { func TestValidateSignatureValues(t *testing.T) {
check := func(expected bool, v byte, r, s *big.Int) { check := func(expected bool, v byte, r, s *big.Int) {
if ValidateSignatureValues(v, r, s) != expected { if ValidateSignatureValues(v, r, s, false) != expected {
t.Errorf("mismatch for v: %d r: %d s: %d want: %v", v, r, s, expected) t.Errorf("mismatch for v: %d r: %d s: %d want: %v", v, r, s, expected)
} }
} }
......
...@@ -58,10 +58,14 @@ import ( ...@@ -58,10 +58,14 @@ import (
var ( var (
context *C.secp256k1_context context *C.secp256k1_context
N *big.Int N *big.Int
HalfN *big.Int
) )
func init() { func init() {
N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
// N / 2 == 57896044618658097711785492504343953926418782139537452191302581570759080747168
HalfN, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", 16)
// around 20 ms on a modern CPU. // around 20 ms on a modern CPU.
context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil) C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil)
......
...@@ -610,13 +610,14 @@ type callmsg struct { ...@@ -610,13 +610,14 @@ type callmsg struct {
} }
// accessor boilerplate to implement core.Message // accessor boilerplate to implement core.Message
func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil } func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil }
func (m callmsg) Nonce() uint64 { return m.from.Nonce() } func (m callmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
func (m callmsg) To() *common.Address { return m.to } func (m callmsg) Nonce() uint64 { return m.from.Nonce() }
func (m callmsg) GasPrice() *big.Int { return m.gasPrice } func (m callmsg) To() *common.Address { return m.to }
func (m callmsg) Gas() *big.Int { return m.gas } func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
func (m callmsg) Value() *big.Int { return m.value } func (m callmsg) Gas() *big.Int { return m.gas }
func (m callmsg) Data() []byte { return m.data } func (m callmsg) Value() *big.Int { return m.value }
func (m callmsg) Data() []byte { return m.data }
type CallArgs struct { type CallArgs struct {
From common.Address `json:"from"` From common.Address `json:"from"`
......
...@@ -25,9 +25,10 @@ var ( ...@@ -25,9 +25,10 @@ var (
MaximumExtraDataSize = big.NewInt(32) // Maximum size extra data may be after Genesis. MaximumExtraDataSize = big.NewInt(32) // Maximum size extra data may be after Genesis.
ExpByteGas = big.NewInt(10) // Times ceil(log256(exponent)) for the EXP instruction. ExpByteGas = big.NewInt(10) // Times ceil(log256(exponent)) for the EXP instruction.
SloadGas = big.NewInt(50) // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. SloadGas = big.NewInt(50) // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
CallValueTransferGas = big.NewInt(9000) // Paid for CALL when the value transfor is non-zero. CallValueTransferGas = big.NewInt(9000) // Paid for CALL when the value transfer is non-zero.
CallNewAccountGas = big.NewInt(25000) // Paid for CALL when the destination address didn't exist prior. CallNewAccountGas = big.NewInt(25000) // Paid for CALL when the destination address didn't exist prior.
TxGas = big.NewInt(21000) // Per transaction. NOTE: Not payable on data of calls between transactions. TxGas = big.NewInt(21000) // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
TxGasContractCreation = big.NewInt(53000) // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
TxDataZeroGas = big.NewInt(4) // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. TxDataZeroGas = big.NewInt(4) // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations. DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
QuadCoeffDiv = big.NewInt(512) // Divisor for the quadratic particle of the memory cost equation. QuadCoeffDiv = big.NewInt(512) // Divisor for the quadratic particle of the memory cost equation.
......
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package params
import "math/big"
// TODO: set exact block number after community consensus is reached.
var HomesteadBlock *big.Int = big.NewInt(0)
func IsHomestead(blockNumber *big.Int) bool {
// for unit tests TODO: flip to true after homestead is live
if blockNumber == nil {
return false
}
return blockNumber.Cmp(HomesteadBlock) >= 0
}
...@@ -148,12 +148,12 @@ func runBlockTests(bt map[string]*BlockTest, skipTests []string) error { ...@@ -148,12 +148,12 @@ func runBlockTests(bt map[string]*BlockTest, skipTests []string) error {
} }
for name, test := range bt { for name, test := range bt {
// if the test should be skipped, return if skipTest[name] || name != "wallet2outOf3txsRevoke" {
if skipTest[name] {
glog.Infoln("Skipping block test", name) glog.Infoln("Skipping block test", name)
continue continue
} }
// test the block // test the block
//fmt.Println("BlockTest name:", name)
if err := runBlockTest(test); err != nil { if err := runBlockTest(test); err != nil {
return fmt.Errorf("%s: %v", name, err) return fmt.Errorf("%s: %v", name, err)
} }
...@@ -185,6 +185,7 @@ func runBlockTest(test *BlockTest) error { ...@@ -185,6 +185,7 @@ func runBlockTest(test *BlockTest) error {
return err return err
} }
cm := ethereum.BlockChain() cm := ethereum.BlockChain()
//vm.Debug = true
validBlocks, err := test.TryBlocksInsert(cm) validBlocks, err := test.TryBlocksInsert(cm)
if err != nil { if err != nil {
return err return err
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -2464,7 +2464,7 @@ ...@@ -2464,7 +2464,7 @@
"out" : "0x60003560e060020a9004806343d726d61461004257806391b7f5ed14610050578063d686f9ee14610061578063f5bade661461006f578063fcfff16f1461008057005b61004a6101de565b60006000f35b61005b6004356100bf565b60006000f35b610069610304565b60006000f35b61007a60043561008e565b60006000f35b6100886100f0565b60006000f35b600054600160a060020a031633600160a060020a031614156100af576100b4565b6100bc565b806001819055505b50565b600054600160a060020a031633600160a060020a031614156100e0576100e5565b6100ed565b806002819055505b50565b600054600160a060020a031633600160a060020a031614806101255750600354600160a060020a031633600160a060020a0316145b61012e57610161565b60016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a16101dc565b60045460011480610173575060015434105b6101b85760016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a142600581905550336003819055506101db565b33600160a060020a03166000346000600060006000848787f16101d757005b5050505b5b565b60006004546000146101ef576101f4565b610301565b600054600160a060020a031633600160a060020a031614801561022c5750600054600160a060020a0316600354600160a060020a0316145b61023557610242565b6000600481905550610301565b600354600160a060020a031633600160a060020a03161461026257610300565b600554420360025402905060015481116102c757600354600160a060020a0316600082600154036000600060006000848787f161029b57005b505050600054600160a060020a03166000826000600060006000848787f16102bf57005b5050506102ee565b600054600160a060020a031660006001546000600060006000848787f16102ea57005b5050505b60006004819055506000546003819055505b5b50565b6000600054600160a060020a031633600160a060020a031614156103275761032c565b61037e565b600554420360025402905060015481116103455761037d565b600054600160a060020a031660006001546000600060006000848787f161036857005b50505060006004819055506000546003819055505b5b5056", "out" : "0x60003560e060020a9004806343d726d61461004257806391b7f5ed14610050578063d686f9ee14610061578063f5bade661461006f578063fcfff16f1461008057005b61004a6101de565b60006000f35b61005b6004356100bf565b60006000f35b610069610304565b60006000f35b61007a60043561008e565b60006000f35b6100886100f0565b60006000f35b600054600160a060020a031633600160a060020a031614156100af576100b4565b6100bc565b806001819055505b50565b600054600160a060020a031633600160a060020a031614156100e0576100e5565b6100ed565b806002819055505b50565b600054600160a060020a031633600160a060020a031614806101255750600354600160a060020a031633600160a060020a0316145b61012e57610161565b60016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a16101dc565b60045460011480610173575060015434105b6101b85760016004819055507f59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a560006000a142600581905550336003819055506101db565b33600160a060020a03166000346000600060006000848787f16101d757005b5050505b5b565b60006004546000146101ef576101f4565b610301565b600054600160a060020a031633600160a060020a031614801561022c5750600054600160a060020a0316600354600160a060020a0316145b61023557610242565b6000600481905550610301565b600354600160a060020a031633600160a060020a03161461026257610300565b600554420360025402905060015481116102c757600354600160a060020a0316600082600154036000600060006000848787f161029b57005b505050600054600160a060020a03166000826000600060006000848787f16102bf57005b5050506102ee565b600054600160a060020a031660006001546000600060006000848787f16102ea57005b5050505b60006004819055506000546003819055505b5b50565b6000600054600160a060020a031633600160a060020a031614156103275761032c565b61037e565b600554420360025402905060015481116103455761037d565b600054600160a060020a031660006001546000600060006000848787f161036857005b50505060006004819055506000546003819055505b5b5056",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x059714", "balance" : "0x061414",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
...@@ -2483,14 +2483,14 @@ ...@@ -2483,14 +2483,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x09184e6b824c", "balance" : "0x09184e6b054c",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "5500215cdbf8165ca47720ad088ae49c2441560cdf267f1c946ae7b9807cb1d4", "postStateRoot" : "b2dfcdafc749ca42b433c9a2f0c9f1375867a776d6389631b83c56928fcc3adc",
"pre" : { "pre" : {
"6295ee1b4f6dd65047762f924ecd367c17eabf8f" : { "6295ee1b4f6dd65047762f924ecd367c17eabf8f" : {
"balance" : "0x0186a0", "balance" : "0x0186a0",
...@@ -2536,7 +2536,7 @@ ...@@ -2536,7 +2536,7 @@
"out" : "0x396000f3006000355415600957005b60", "out" : "0x396000f3006000355415600957005b60",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0xb44e", "balance" : "0x01314e",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
...@@ -2551,14 +2551,14 @@ ...@@ -2551,14 +2551,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0de0b6b3a761c512", "balance" : "0x0de0b6b3a7614812",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "e0911f5b8035d9192581b3a82ddb0a32955e880088c49e92936789be2310ef90", "postStateRoot" : "a8d7d1b8699bdceade31abacca281e2570461a3083f2767cbaad1ed08581cf2b",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0de0b6b3a7640000", "balance" : "0x0de0b6b3a7640000",
...@@ -2570,7 +2570,7 @@ ...@@ -2570,7 +2570,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "0x6001600155601080600c6000396000f3006000355415600957005b60203560003555", "data" : "0x6001600155601080600c6000396000f3006000355415600957005b60203560003555",
"gasLimit" : "0xb44e", "gasLimit" : "0x1314e",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -2591,30 +2591,15 @@ ...@@ -2591,30 +2591,15 @@
], ],
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0xa7ce",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"6295ee1b4f6dd65047762f924ecd367c17eabf8f" : {
"balance" : "0x0186a0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
"0x01" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0de0b6b3a761d192", "balance" : "0x0de0b6b3a7640000",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x00",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "6dcd1874a8295fa628ca7c100e9fa6248e74b92afd9a7b8511879078dfc2f007", "postStateRoot" : "517f2cdf6adb1a644878c390ffab4e130f1bed4b498ef7ce58c5addd98d61018",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0de0b6b3a7640000", "balance" : "0x0de0b6b3a7640000",
...@@ -2648,36 +2633,28 @@ ...@@ -2648,36 +2633,28 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x0de0b6b3a7658689", "balance" : "0x0de0b6b3a76586a0",
"code" : "0x7f6001600155601080600c6000396000f3006000355415600957005b602035600060005260356020536055602153602260006017f0", "code" : "0x7f6001600155601080600c6000396000f3006000355415600957005b602035600060005260356020536055602153602260006017f0",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x011d70", "balance" : "0x0129ef",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0de0b6b3a7615bf0", "balance" : "0x0de0b6b3a7614f71",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
},
"d2571607e241ecf590ed94b12d87c94babe36db6" : {
"balance" : "0x17",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
"0x01" : "0x01"
}
} }
}, },
"postStateRoot" : "86a4e893a117e2e38a77247e6b01a29680bb0e0fc68807885231f527720d18c0", "postStateRoot" : "e0d7037b9e6dc379cb187ed0a6841173c641887db375dc1a7c6d7dd140fc867b",
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "0x0de0b6b3a7640000", "balance" : "0x0de0b6b3a7640000",
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -640,7 +640,7 @@ ...@@ -640,7 +640,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "0x600a80600c6000396000f200600160008035811a8100", "data" : "0x600a80600c6000396000f200600160008035811a8100",
"gasLimit" : "0x56a0", "gasLimit" : "0xd3a0",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -681,7 +681,7 @@ ...@@ -681,7 +681,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "0x600a80600c6000396000f200600160008035811a8100", "data" : "0x600a80600c6000396000f200600160008035811a8100",
"gasLimit" : "0x55f0", "gasLimit" : "0xd2f0",
"gasPrice" : "0x03", "gasPrice" : "0x03",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -858,24 +858,24 @@ ...@@ -858,24 +858,24 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x9c40", "balance" : "0x011940",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x2710", "balance" : "0x0bb8",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "513a8c6605f11e258856d079b6d9c3cc228eb5f4788977a5a04a0a05d54a5b99", "postStateRoot" : "961c54e78bf240486182b172fbb7d740e2da28906ea11dcb1266cb20e8862b5a",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xc350", "balance" : "0x0124f8",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
...@@ -884,7 +884,7 @@ ...@@ -884,7 +884,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "0x6000f1", "data" : "0x6000f1",
"gasLimit" : "0x9c40", "gasLimit" : "0x011940",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -913,21 +913,21 @@ ...@@ -913,21 +913,21 @@
} }
}, },
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x2bbe", "balance" : "0x76bc",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x015ad3", "balance" : "0x010fd5",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "5e2d18e12d28a412e04a57800ba998a10739ee10aa35127cfcb8e675c2bbd290", "postStateRoot" : "e0b65a3a37e8268cf5b5a41ef02bba89826e1a436636f182645214e5235c9c79",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0", "balance" : "0x0186a0",
...@@ -939,7 +939,7 @@ ...@@ -939,7 +939,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "0x600a80600c6000396000fff2ffff600160008035811a81", "data" : "0x600a80600c6000396000fff2ffff600160008035811a81",
"gasLimit" : "0x59d8", "gasLimit" : "0xd6d8",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -961,21 +961,21 @@ ...@@ -961,21 +961,21 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x7f57", "balance" : "0xfc57",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x010749", "balance" : "0x8a49",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "5733390723cba15437e2ee1d1649b1189eeab81f092f7883171d9f7a4b9f514e", "postStateRoot" : "9e36cea9425d4207793943218f40eedc0c7b9505693c74e1c39b27b2de902d13",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0", "balance" : "0x0186a0",
...@@ -987,7 +987,7 @@ ...@@ -987,7 +987,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "0x600a80600c6000396000f200600160008035811a8100", "data" : "0x600a80600c6000396000f200600160008035811a8100",
"gasLimit" : "0x7f57", "gasLimit" : "0xfc57",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -1009,7 +1009,7 @@ ...@@ -1009,7 +1009,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x56bc", "balance" : "0xd3bc",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
...@@ -1023,14 +1023,14 @@ ...@@ -1023,14 +1023,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x012fe3", "balance" : "0xb2e3",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "b2de012ac480412426664a68a009920fb4ce8c9651543900c440070e8e286644", "postStateRoot" : "99f11d9bf8862c426bc510d7c6d2ed4c6f353411b782f8a3a268268319b9b689",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0", "balance" : "0x0186a0",
...@@ -1042,7 +1042,7 @@ ...@@ -1042,7 +1042,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "0x600a80600c600039600000f20000600160008035811a81", "data" : "0x600a80600c600039600000f20000600160008035811a81",
"gasLimit" : "0x59d8", "gasLimit" : "0xd6d8",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -1064,21 +1064,21 @@ ...@@ -1064,21 +1064,21 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x59d8", "balance" : "0xd6d8",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x012cc8", "balance" : "0xafc8",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "b231c450a665052fe6577f93350aeedb39ceeceacc2ba93a5ee640dd63f9d29a", "postStateRoot" : "b2f8ca928c2981cc192c854df4736810593c8fd90783416d84b4a0f1e0fea952",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0", "balance" : "0x0186a0",
...@@ -1090,7 +1090,7 @@ ...@@ -1090,7 +1090,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "0x600a80600c6000396000f200ff600160008035811a81", "data" : "0x600a80600c6000396000f200ff600160008035811a81",
"gasLimit" : "0x59d8", "gasLimit" : "0xd6d8",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
......
...@@ -240,7 +240,7 @@ ...@@ -240,7 +240,7 @@
"out" : "0x600060006000600060003060405a03f1", "out" : "0x600060006000600060003060405a03f1",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x69e8", "balance" : "0xe6e8",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
...@@ -254,14 +254,14 @@ ...@@ -254,14 +254,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x05f5770e", "balance" : "0x05f4fa0e",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "00056a5cf74634e496d1eba26e3a027b0d2c679333b923053fad7918e882c9aa", "postStateRoot" : "68f497ee77ebf9247fe0c5df49aae2b78bc0010983cec0f79b1cb440652bfd06",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x05f5e100", "balance" : "0x05f5e100",
......
...@@ -340,7 +340,7 @@ ...@@ -340,7 +340,7 @@
"out" : "0x60e060020a600035048063f8a8fd6d14601457005b601a6020565b60006000f35b56", "out" : "0x60e060020a600035048063f8a8fd6d14601457005b601a6020565b60006000f35b56",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x772e", "balance" : "0xf42e",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
...@@ -354,14 +354,14 @@ ...@@ -354,14 +354,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x010f0e", "balance" : "0x920e",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "7d12ba0d5a88efcfc293ed4a5f877db891be20380c0483f1800f19786c35dce2", "postStateRoot" : "a0b82485d35279240c14e3d39dc992f4fe8af2e630902afe6c45c58f58ee2011",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0", "balance" : "0x0186a0",
...@@ -469,7 +469,7 @@ ...@@ -469,7 +469,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "", "data" : "",
"gasLimit" : "0x55f0", "gasLimit" : "0xd6d8",
"gasPrice" : "0x00", "gasPrice" : "0x00",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -491,7 +491,7 @@ ...@@ -491,7 +491,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x5208", "balance" : "0xcf08",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
...@@ -505,14 +505,14 @@ ...@@ -505,14 +505,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x013498", "balance" : "0xb798",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "cf29b86efa1b7f5f999ef519fcc921062924d5c14d78baf491252fbf5a0d85b8", "postStateRoot" : "53f5b84edd82703a225e53e9ae3639729eb8e337098531456998af602b0ded0a",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0", "balance" : "0x0186a0",
...@@ -524,7 +524,7 @@ ...@@ -524,7 +524,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "", "data" : "",
"gasLimit" : "0x55f0", "gasLimit" : "0xd6d8",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
...@@ -2017,7 +2017,7 @@ ...@@ -2017,7 +2017,7 @@
"out" : "0x", "out" : "0x",
"post" : { "post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x5208", "balance" : "0xcf08",
"code" : "0x", "code" : "0x",
"nonce" : "0x00", "nonce" : "0x00",
"storage" : { "storage" : {
...@@ -2031,14 +2031,14 @@ ...@@ -2031,14 +2031,14 @@
} }
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x013498", "balance" : "0xb798",
"code" : "0x", "code" : "0x",
"nonce" : "0x01", "nonce" : "0x01",
"storage" : { "storage" : {
} }
} }
}, },
"postStateRoot" : "cf29b86efa1b7f5f999ef519fcc921062924d5c14d78baf491252fbf5a0d85b8", "postStateRoot" : "53f5b84edd82703a225e53e9ae3639729eb8e337098531456998af602b0ded0a",
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0", "balance" : "0x0186a0",
...@@ -2050,7 +2050,7 @@ ...@@ -2050,7 +2050,7 @@
}, },
"transaction" : { "transaction" : {
"data" : "", "data" : "",
"gasLimit" : "0x5208", "gasLimit" : "0xcf08",
"gasPrice" : "0x01", "gasPrice" : "0x01",
"nonce" : "0x00", "nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
......
This diff is collapsed.
This diff is collapsed.
...@@ -122,6 +122,27 @@ func TestCallCodes(t *testing.T) { ...@@ -122,6 +122,27 @@ func TestCallCodes(t *testing.T) {
} }
} }
func TestDelegateCall(t *testing.T) {
fn := filepath.Join(stateTestDir, "stDelegatecallTest.json")
if err := RunStateTest(fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestDelegateCallCodes1(t *testing.T) {
fn := filepath.Join(stateTestDir, "stCallDelegateCodes.json")
if err := RunStateTest(fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestDelegateCallCodes2(t *testing.T) {
fn := filepath.Join(stateTestDir, "stCallDelegateCodesCallCode.json")
if err := RunStateTest(fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestMemory(t *testing.T) { func TestMemory(t *testing.T) {
fn := filepath.Join(stateTestDir, "stMemoryTest.json") fn := filepath.Join(stateTestDir, "stMemoryTest.json")
if err := RunStateTest(fn, StateSkipTests); err != nil { if err := RunStateTest(fn, StateSkipTests); err != nil {
......
...@@ -125,10 +125,10 @@ func runStateTests(tests map[string]VmTest, skipTests []string) error { ...@@ -125,10 +125,10 @@ func runStateTests(tests map[string]VmTest, skipTests []string) error {
for name, test := range tests { for name, test := range tests {
if skipTest[name] { if skipTest[name] {
glog.Infoln("Skipping state test", name) glog.Infoln("Skipping state test", name)
return nil continue
} }
//fmt.Println("StateTest name:", name) fmt.Println("StateTest:", name)
if err := runStateTest(test); err != nil { if err := runStateTest(test); err != nil {
return fmt.Errorf("%s: %s\n", name, err.Error()) return fmt.Errorf("%s: %s\n", name, err.Error())
} }
...@@ -182,13 +182,16 @@ func runStateTest(test VmTest) error { ...@@ -182,13 +182,16 @@ func runStateTest(test VmTest) error {
// check post state // check post state
for addr, account := range test.Post { for addr, account := range test.Post {
obj := statedb.GetStateObject(common.HexToAddress(addr)) obj := statedb.GetStateObject(common.HexToAddress(addr))
if obj == nil {
return fmt.Errorf("did not find expected post-state account: %s", addr)
}
if obj.Balance().Cmp(common.Big(account.Balance)) != 0 { if obj.Balance().Cmp(common.Big(account.Balance)) != 0 {
return fmt.Errorf("(%x) balance failed. Expected %v, got %v => %v\n", obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance())) return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", obj.Address().Bytes()[:4], common.String2Big(account.Balance), obj.Balance())
} }
if obj.Nonce() != common.String2Big(account.Nonce).Uint64() { if obj.Nonce() != common.String2Big(account.Nonce).Uint64() {
return fmt.Errorf("(%x) nonce failed. Expected %v, got %v\n", obj.Address().Bytes()[:4], account.Nonce, obj.Nonce()) return fmt.Errorf("(%x) nonce failed. Expected: %v have: %v\n", obj.Address().Bytes()[:4], account.Nonce, obj.Nonce())
} }
for addr, value := range account.Storage { for addr, value := range account.Storage {
...@@ -196,14 +199,14 @@ func runStateTest(test VmTest) error { ...@@ -196,14 +199,14 @@ func runStateTest(test VmTest) error {
vexp := common.HexToHash(value) vexp := common.HexToHash(value)
if v != vexp { if v != vexp {
return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", obj.Address().Bytes()[0:4], addr, vexp, v, vexp.Big(), v.Big()) return fmt.Errorf("storage failed:\n%x: %s:\nexpected: %x\nhave: %x\n(%v %v)\n", obj.Address().Bytes(), addr, vexp, v, vexp.Big(), v.Big())
} }
} }
} }
root, _ := statedb.Commit() root, _ := statedb.Commit()
if common.HexToHash(test.PostStateRoot) != root { if common.HexToHash(test.PostStateRoot) != root {
return fmt.Errorf("Post state root error. Expected %s, got %x", test.PostStateRoot, root) return fmt.Errorf("Post state root error. Expected: %s have: %x", test.PostStateRoot, root)
} }
// check logs // check logs
...@@ -232,7 +235,7 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Log ...@@ -232,7 +235,7 @@ func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Log
} }
// Set pre compiled contracts // Set pre compiled contracts
vm.Precompiled = vm.PrecompiledContracts() vm.Precompiled = vm.PrecompiledContracts()
vm.Debug = false
snapshot := statedb.Copy() snapshot := statedb.Copy()
gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"])) gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
......
...@@ -120,7 +120,7 @@ func runTransactionTest(txTest TransactionTest) (err error) { ...@@ -120,7 +120,7 @@ func runTransactionTest(txTest TransactionTest) (err error) {
return nil return nil
} else { } else {
// RLP decoding failed but is expected to succeed (test FAIL) // RLP decoding failed but is expected to succeed (test FAIL)
return fmt.Errorf("RLP decoding failed when expected to succeed: ", err) return fmt.Errorf("RLP decoding failed when expected to succeed: %s", err)
} }
} }
...@@ -142,7 +142,7 @@ func runTransactionTest(txTest TransactionTest) (err error) { ...@@ -142,7 +142,7 @@ func runTransactionTest(txTest TransactionTest) (err error) {
return nil return nil
} else { } else {
// RLP decoding works and validations pass (test FAIL) // RLP decoding works and validations pass (test FAIL)
return fmt.Errorf("Field validations failed after RLP decoding: ", validationError) return fmt.Errorf("Field validations failed after RLP decoding: %s", validationError)
} }
} }
return errors.New("Should not happen: verify RLP decoding and field validation") return errors.New("Should not happen: verify RLP decoding and field validation")
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment