diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index dd9c81fd41..fa2d740e45 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -289,6 +289,8 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int { next := new(big.Int).Add(parent.Number, common.Big1) switch { + case config.IsMetropolis(next): + return calcDifficultyMetropolis(time, parent) case config.IsHomestead(next): return calcDifficultyHomestead(time, parent) default: @@ -299,10 +301,56 @@ func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Heade // Some weird constants to avoid constant memory allocs for them. var ( expDiffPeriod = big.NewInt(100000) + big9 = big.NewInt(9) big10 = big.NewInt(10) bigMinus99 = big.NewInt(-99) ) +func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int { + bigTime := new(big.Int).SetUint64(time) + bigParentTime := new(big.Int).Set(parent.Time) + + // adj_factor = max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99) + var x *big.Int + if parent.UncleHash == types.EmptyUncleHash { + x = big.NewInt(1) + } else { + x = big.NewInt(2) + } + z := new(big.Int).Sub(bigTime, bigParentTime) + z.Div(z, big9) + x.Sub(x, z) + + // 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 := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) + x.Mul(y, x) + x.Add(parent.Difficulty, x) + + // minimum difficulty can ever be (before exponential factor) + if x.Cmp(params.MinimumDifficulty) < 0 { + x.Set(params.MinimumDifficulty) + } + + // for the exponential factor + periodCount := new(big.Int).Add(parent.Number, common.Big1) + periodCount.Div(periodCount, expDiffPeriod) + + // the exponential factor, commonly referred 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 +} + // calcDifficultyHomestead 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. The calculation uses the Homestead rules. diff --git a/core/state_processor.go b/core/state_processor.go index 90f5a4f60c..158a9fa2df 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -105,10 +105,15 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common // Update the state with pending changes usedGas.Add(usedGas, gas) + var root []byte + if config.IsMetropolis(header.Number) { + statedb.Finalise() + } else { + root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() + } // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing wether the root touch-delete accounts. - root := statedb.IntermediateRoot(config.IsEIP158(header.Number)) - receipt := types.NewReceipt(root.Bytes(), usedGas) + receipt := types.NewReceipt(root, usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) // if the transaction created a contract, store the creation address in the receipt. diff --git a/core/state_transition.go b/core/state_transition.go index 0ae9d7fcbf..c6d7a5b68a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -236,7 +236,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big vmerr error ) if contractCreation { - ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) + createAddressFn := vm.CreateAddressFn(st.evm.ChainConfig(), st.evm.BlockNumber, sender.Address(), st.state.GetNonce(sender.Address()), st.data) + ret, _, st.gas, vmerr = evm.Create(sender, createAddressFn, st.data, st.gas, st.value) } else { // Increment the nonce for the next transaction st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1) diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index edbd64ba4e..eb2e5d42b4 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -13,7 +13,7 @@ import ( func (r Receipt) MarshalJSON() ([]byte, error) { type Receipt struct { - PostState hexutil.Bytes `json:"root" gencodec:"required"` + PostState hexutil.Bytes `json:"root"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -34,7 +34,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { func (r *Receipt) UnmarshalJSON(input []byte) error { type Receipt struct { - PostState hexutil.Bytes `json:"root" gencodec:"required"` + PostState hexutil.Bytes `json:"root"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` Bloom *Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -46,10 +46,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { if err := json.Unmarshal(input, &dec); err != nil { return err } - if dec.PostState == nil { - return errors.New("missing required field 'root' for Receipt") + if dec.PostState != nil { + r.PostState = dec.PostState } - r.PostState = dec.PostState if dec.CumulativeGasUsed == nil { return errors.New("missing required field 'cumulativeGasUsed' for Receipt") } diff --git a/core/types/receipt.go b/core/types/receipt.go index ef6f6a2bb2..46d2530bbc 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -31,7 +31,7 @@ import ( // Receipt represents the results of a transaction. type Receipt struct { // Consensus fields - PostState []byte `json:"root" gencodec:"required"` + PostState []byte `json:"root"` CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -48,6 +48,19 @@ type receiptMarshaling struct { GasUsed *hexutil.Big } +type homesteadReceiptRLP struct { + PostState []byte + CumulativeGasUsed *big.Int + Bloom Bloom + Logs []*Log +} + +type metropolisReceiptRLP struct { + CumulativeGasUsed *big.Int + Bloom Bloom + Logs []*Log +} + // NewReceipt creates a barebone transaction receipt, copying the init fields. func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} @@ -56,23 +69,28 @@ func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt // into an RLP stream. func (r *Receipt) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs}) + if r.PostState == nil { + return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs}) + } else { + return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs}) + } } // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt // from an RLP stream. func (r *Receipt) DecodeRLP(s *rlp.Stream) error { - var receipt struct { - PostState []byte - CumulativeGasUsed *big.Int - Bloom Bloom - Logs []*Log - } - if err := s.Decode(&receipt); err != nil { + raw, err := s.Raw() + if err != nil { return err } - r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs - return nil + var hr homesteadReceiptRLP + var mr metropolisReceiptRLP + if err = rlp.DecodeBytes(raw, &mr); err == nil { + r.CumulativeGasUsed, r.Bloom, r.Logs = mr.CumulativeGasUsed, mr.Bloom, mr.Logs + } else if err = rlp.DecodeBytes(raw, &hr); err == nil { + r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = hr.PostState[:], hr.CumulativeGasUsed, hr.Bloom, hr.Logs + } + return err } // String implements the Stringer interface. diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index ba4f2aa03a..1f508ddc22 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -45,6 +45,8 @@ type sigCache struct { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { var signer Signer switch { + case config.IsMetropolis(blockNumber): + signer = NewEIP86Signer(config.ChainId) case config.IsEIP155(blockNumber): signer = NewEIP155Signer(config.ChainId) case config.IsHomestead(blockNumber): @@ -88,6 +90,10 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) { pubkey, err := signer.PublicKey(tx) if err != nil { + if err == errAbstractSigner { + return abstractSignerAddress, nil + } + return common.Address{}, err } var addr common.Address @@ -108,6 +114,37 @@ type Signer interface { Equal(Signer) bool } +// EIP86Signer implements the the abstract signing feature +type EIP86Signer struct { + EIP155Signer +} + +func NewEIP86Signer(chainId *big.Int) EIP86Signer { + return EIP86Signer{ + EIP155Signer: NewEIP155Signer(chainId), + } +} + +func (s EIP86Signer) Equal(s2 Signer) bool { + _, ok := s2.(EIP86Signer) + return ok && s.EIP155Signer.Equal(s2) +} + +// isAbstractSigner checks whether the transaction signature is that of +// the abstract signer. The abstract signer is determined by V being equal +// to the chain identifier and r and s being 0. +func isAbstractSigner(tx *Transaction, chainId *big.Int) bool { + v, r, s := tx.RawSignatureValues() + return v.Cmp(chainId) == 0 && r.BitLen() == 0 && s.BitLen() == 0 +} + +func (s EIP86Signer) PublicKey(tx *Transaction) ([]byte, error) { + if isAbstractSigner(tx, s.chainId) { + return nil, errAbstractSigner + } + return s.EIP155Signer.PublicKey(tx) +} + // EIP155Transaction implements TransactionInterface using the // EIP155 rules type EIP155Signer struct { diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 90b2f913e6..ea84877464 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -22,7 +22,9 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "golang.org/x/crypto/ripemd160" @@ -46,6 +48,19 @@ var PrecompiledContracts = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{4}): &dataCopy{}, } +// PrecompiledContractsMetropolis contains the default set of ethereum contracts +// for metropolis hardfork +var PrecompiledContractsMetropolis = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{1}): &ecrecover{}, + common.BytesToAddress([]byte{2}): &sha256hash{}, + common.BytesToAddress([]byte{3}): &ripemd160hash{}, + common.BytesToAddress([]byte{4}): &dataCopy{}, + common.BytesToAddress([]byte{5}): &bigModexp{}, + common.BytesToAddress([]byte{6}): &bn256Add{}, + common.BytesToAddress([]byte{7}): &bn256ScalarMul{}, + common.BytesToAddress([]byte{8}): &pairing{}, +} + // RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { gas := p.RequiredGas(input) @@ -135,3 +150,188 @@ func (c *dataCopy) RequiredGas(input []byte) uint64 { func (c *dataCopy) Run(in []byte) ([]byte, error) { return in, nil } + +// bigModexp implements a native big integer exponential modular operation. +type bigModexp struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *bigModexp) RequiredGas(input []byte) uint64 { + // TODO reword required gas to have error reporting and convert arithmetic + // to uint64. + if len(input) < 3*32 { + input = append(input, make([]byte, 3*32-len(input))...) + } + var ( + baseLen = new(big.Int).SetBytes(input[:31]) + expLen = math.BigMax(new(big.Int).SetBytes(input[32:64]), big.NewInt(1)) + modLen = new(big.Int).SetBytes(input[65:97]) + ) + x := new(big.Int).Set(math.BigMax(baseLen, modLen)) + x.Mul(x, x) + x.Mul(x, expLen) + x.Div(x, new(big.Int).SetUint64(params.QuadCoeffDiv)) + + return x.Uint64() +} + +func (c *bigModexp) Run(input []byte) ([]byte, error) { + if len(input) < 3*32 { + input = append(input, make([]byte, 3*32-len(input))...) + } + // why 32-byte? These values won't fit anyway + var ( + baseLen = new(big.Int).SetBytes(input[:32]).Uint64() + expLen = new(big.Int).SetBytes(input[32:64]).Uint64() + modLen = new(big.Int).SetBytes(input[64:96]).Uint64() + ) + + input = input[96:] + if uint64(len(input)) < baseLen { + input = append(input, make([]byte, baseLen-uint64(len(input)))...) + } + base := new(big.Int).SetBytes(input[:baseLen]) + + input = input[baseLen:] + if uint64(len(input)) < expLen { + input = append(input, make([]byte, expLen-uint64(len(input)))...) + } + exp := new(big.Int).SetBytes(input[:expLen]) + + input = input[expLen:] + if uint64(len(input)) < modLen { + input = append(input, make([]byte, modLen-uint64(len(input)))...) + } + mod := new(big.Int).SetBytes(input[:modLen]) + + return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), len(input[:modLen])), nil +} + +type bn256Add struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *bn256Add) RequiredGas(input []byte) uint64 { + return 0 // TODO +} + +func (c *bn256Add) Run(in []byte) ([]byte, error) { + in = common.RightPadBytes(in, 128) + + x, onCurve := new(bn256.G1).Unmarshal(in[:64]) + if !onCurve { + return nil, errNotOnCurve + } + gx, gy, _, _ := x.CurvePoints() + if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + + y, onCurve := new(bn256.G1).Unmarshal(in[:64]) + if !onCurve { + return nil, errNotOnCurve + } + gx, gy, _, _ = x.CurvePoints() + if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + x.Add(x, y) + + return x.Marshal(), nil +} + +type bn256ScalarMul struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 { + return 0 // TODO +} + +func (c *bn256ScalarMul) Run(in []byte) ([]byte, error) { + in = common.RightPadBytes(in, 96) + + g1, onCurve := new(bn256.G1).Unmarshal(in[:64]) + if !onCurve { + return nil, errNotOnCurve + } + x, y, _, _ := g1.CurvePoints() + if x.Cmp(bn256.P) >= 0 || y.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + g1.ScalarMult(g1, new(big.Int).SetBytes(in[64:96])) + + return g1.Marshal(), nil +} + +// pairing implements a pairing pre-compile for the bn256 curve +type pairing struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *pairing) RequiredGas(input []byte) uint64 { + return 0 // TODO +} + +const pairSize = 192 + +var ( + true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + fals32Byte = make([]byte, 32) + errNotOnCurve = errors.New("point not on elliptic curve") + errInvalidCurvePoint = errors.New("invalid elliptic curve point") +) + +func (c *pairing) Run(in []byte) ([]byte, error) { + if len(in) == 0 { + return true32Byte, nil + } + + if len(in)%pairSize > 0 { + return nil, errBadPrecompileInput + } + + var ( + g1s []*bn256.G1 + g2s []*bn256.G2 + ) + for i := 0; i < len(in); i += pairSize { + g1, onCurve := new(bn256.G1).Unmarshal(in[i : i+64]) + if !onCurve { + return nil, errNotOnCurve + } + + x, y, _, _ := g1.CurvePoints() + if x.Cmp(bn256.P) >= 0 || y.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + + g2, onCurve := new(bn256.G2).Unmarshal(in[i+64 : i+192]) + if !onCurve { + return nil, errNotOnCurve + } + x2, y2, _, _ := g2.CurvePoints() + if x2.Real().Cmp(bn256.P) >= 0 || x2.Imag().Cmp(bn256.P) >= 0 || + y2.Real().Cmp(bn256.P) >= 0 || y2.Imag().Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + + g1s = append(g1s, g1) + g2s = append(g2s, g2) + } + + isOne := bn256.PairingCheck(g1s, g2s) + if isOne { + return true32Byte, nil + } + + return fals32Byte, nil +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 830a8f69d9..2b4070ede7 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -1 +1,35 @@ package vm + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +const input = "" + +func TestPairing(t *testing.T) { + pairing := &pairing{} + + for i, test := range []struct { + input string + valid int + }{ + {"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1}, + {"2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1}, + {"0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1}, + {"2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", 1}, + {"20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1}, + {"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 0}, + } { + r, err := pairing.Run(common.FromHex(test.input)) + if err != nil { + t.Error(i, ":", err) + } + + if int(r[31]) != test.valid { + t.Error(i, "expected", test.valid, "but was", r[31]) + } + } + +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 9296cc7cac..38916cc956 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -37,6 +37,10 @@ type ( func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, error) { if contract.CodeAddr != nil { precompiledContracts := PrecompiledContracts + if evm.ChainConfig().IsMetropolis(evm.BlockNumber) { + precompiledContracts = PrecompiledContractsMetropolis + } + if p := precompiledContracts[*contract.CodeAddr]; p != nil { return RunPrecompiledContract(p, input, contract) } @@ -100,8 +104,8 @@ type EVM struct { abort int32 } -// NewEVM retutrns a new EVM evmironment. The returned EVM is not thread safe -// and should only ever be used *once*. +// NewEVM retutrns a new EVM . The returned EVM is not thread safe and should +// only ever be used *once*. func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { evm := &EVM{ Context: ctx, @@ -121,6 +125,51 @@ func (evm *EVM) Cancel() { atomic.StoreInt32(&evm.abort, 1) } +func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + + // Depth check execution. Fail if we're trying to execute above the + // limit. + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + + // make sure the readonly is only set if we aren't in readonly yet + // this makes also sure that the readonly flag isn't removed for + // child calls. + if !evm.interpreter.readonly { + evm.interpreter.readonly = true + defer func() { evm.interpreter.readonly = false }() + } + + var ( + to = AccountRef(addr) + snapshot = evm.StateDB.Snapshot() + ) + if !evm.StateDB.Exist(addr) { + return nil, gas, nil + } + + // initialise a new contract and set the code that is to be used by the + // EVM. The contract is a scoped evmironment for this execution context + // only. + contract := NewContract(caller, to, new(big.Int), gas) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + ret, err = evm.interpreter.Run(snapshot, contract, input) + // When an error was returned by the EVM or when setting the creation code + // above we revert to the snapshot and consume any gas remaining. Additionally + // when we're in homestead this also counts for code storage gas errors. + if err != nil { + contract.UseGas(contract.Gas) + + evm.StateDB.RevertToSnapshot(snapshot) + } + return ret, contract.Gas, err +} + // Call executes the contract associated with the addr with the given input as parameters. It also handles any // necessary value transfer required and takes the necessary steps to create accounts and reverses the state in // case of an execution error or failed value transfer. @@ -241,7 +290,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // Create creates a new contract using code as deployment code. -func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { +func (evm *EVM) Create(caller ContractRef, createAddress addressCreationFn, code []byte, gas uint64, value *big.Int) (ret []byte, _ common.Address, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, common.Address{}, gas, nil } @@ -260,7 +309,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I evm.StateDB.SetNonce(caller.Address(), nonce+1) snapshot := evm.StateDB.Snapshot() - contractAddr = crypto.CreateAddress(caller.Address(), nonce) + + contractAddr := createAddress() + evm.StateDB.CreateAccount(contractAddr) if evm.ChainConfig().IsEIP158(evm.BlockNumber) { evm.StateDB.SetNonce(contractAddr, 1) @@ -312,3 +363,5 @@ func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } // Interpreter returns the EVM interpreter func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter } + +type addressCreationFn func() common.Address diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 761ca44507..5921e26631 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -91,6 +91,32 @@ func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *St return gas, nil } +func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + + var overflow bool + if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { + return 0, errGasUintOverflow + } + + words, overflow := bigUint64(stack.Back(2)) + if overflow { + return 0, errGasUintOverflow + } + + if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + return 0, errGasUintOverflow + } + + if gas, overflow = math.SafeAdd(gas, words); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( y, x = stack.Back(1), stack.Back(0) @@ -423,6 +449,35 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St return gas, nil } +func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + panic("verify this one") + + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { + return 0, errGasUintOverflow + } + + cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + // Replace the stack item with the new gas calculation. This means that + // either the original item is left on the stack or the item is replaced by: + // (availableGas - gas) * 63 / 64 + // We replace the stack item so that it's available when the opCall instruction is + // called. + stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) + + if gas, overflow = math.SafeAdd(gas, cg); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index f5164fcdd4..353632f13a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,6 +17,7 @@ package vm import ( + "errors" "fmt" "math/big" @@ -28,7 +29,9 @@ import ( ) var ( - bigZero = new(big.Int) + bigZero = new(big.Int) + errWriteProtection = errors.New("evm: write protection") + errReadOutOfBound = errors.New("evm: read out of bound") ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -539,6 +542,18 @@ func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac return nil, nil } +func CreateAddressFn(chainConfig *params.ChainConfig, blockNumber *big.Int, senderAddress common.Address, nonce uint64, input []byte) func() common.Address { + if chainConfig.IsMetropolis(blockNumber) { + return func() common.Address { + return common.BytesToAddress(crypto.Keccak256(senderAddress.Bytes(), crypto.Keccak256(input))[12:]) + } + } else { + return func() common.Address { + return crypto.CreateAddress(senderAddress, nonce) + } + } +} + func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( value = stack.pop() @@ -550,8 +565,10 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S gas -= gas / 64 } + createAddressFn := CreateAddressFn(evm.ChainConfig(), evm.BlockNumber, contract.Address(), evm.StateDB.GetNonce(contract.Address()), input) + contract.UseGas(gas) - _, addr, returnGas, suberr := evm.Create(contract, input, gas, value) + _, addr, returnGas, suberr := evm.Create(contract, createAddressFn, input, gas, value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must @@ -570,6 +587,71 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S return nil, nil } +func opCreate2(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + value = stack.pop() + salt = stack.pop() + offset, size = stack.pop(), stack.pop() + input = memory.Get(offset.Int64(), size.Int64()) + gas = contract.Gas + ) + if evm.ChainConfig().IsEIP150(evm.BlockNumber) { + gas -= gas / 64 + } + + createAddress := func() common.Address { + return common.BytesToAddress(crypto.Keccak256(contract.Address().Bytes(), salt.Bytes(), crypto.Keccak256(input))[12:]) + } + + contract.UseGas(gas) + _, addr, returnGas, suberr := evm.Create(contract, createAddress, input, gas, value) + // Push item on the stack based on the returned error. If the ruleset is + // homestead we must check for CodeStoreOutOfGasError (homestead only + // rule) and treat as an error, if the ruleset is frontier we must + // ignore this error and pretend the operation was successful. + if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { + stack.push(new(big.Int)) + } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { + stack.push(new(big.Int)) + } else { + stack.push(addr.Big()) + } + contract.Gas += returnGas + + evm.interpreter.intPool.put(value, offset, size) + + return nil, nil +} + +func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // pop gas + gas := stack.pop().Uint64() + // pop address + addr := stack.pop() + // pop input size and offset + inOffset, inSize := stack.pop(), stack.pop() + // pop return size and offset + retOffset, retSize := stack.pop(), stack.pop() + + address := common.BigToAddress(addr) + + // Get the arguments from the memory + args := memory.Get(inOffset.Int64(), inSize.Int64()) + + ret, returnGas, err := evm.StaticCall(contract, address, args, gas) + if err != nil { + stack.push(new(big.Int)) + } else { + stack.push(big.NewInt(1)) + + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + } + contract.Gas += returnGas + + evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + return ret, nil +} + func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { gas := stack.pop().Uint64() // pop gas and value of the stack. @@ -665,6 +747,14 @@ func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S return ret, nil } +func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + offset, size := stack.pop(), stack.pop() + ret := memory.GetPtr(offset.Int64(), size.Int64()) + + evm.interpreter.intPool.put(offset, size) + return ret, nil +} + func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } @@ -678,6 +768,28 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack * return nil, nil } +func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(evm.interpreter.returnData)))) + return nil, nil +} + +func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + mOff = stack.pop() + cOff = stack.pop() + l = stack.pop() + ) + defer evm.interpreter.intPool.put(mOff, cOff, l) + + cEnd := new(big.Int).Add(cOff, l) + if cEnd.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < cEnd.Uint64() { + return nil, errReadOutOfBound + } + memory.Set(mOff.Uint64(), l.Uint64(), evm.interpreter.returnData[cOff.Uint64():cEnd.Uint64()]) + + return nil, nil +} + // following functions are used by the instruction jump table // make log instruction function diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 545f7d6502..a64d1bab5a 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -51,10 +51,9 @@ type Config struct { JumpTable [256]operation } -// Interpreter is used to run Ethereum based contracts and will utilise the -// passed evmironment to query external sources for state information. -// The Interpreter will run the byte code VM or JIT VM based on the passed -// configuration. +// Interpreter is capable of interpreting Ethereum Byte code and uses the passed +// Ethereum Virtual Machine to query for auxiliary data such as state, block and +// caller information. type Interpreter struct { evm *EVM cfg Config @@ -62,6 +61,8 @@ type Interpreter struct { intPool *intPool readonly bool + // returnData contains the last call's return data + returnData []byte } // NewInterpreter returns a new instance of the Interpreter. @@ -71,6 +72,8 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter { // we'll set the default jump table. if !cfg.JumpTable[STOP].valid { switch { + case evm.ChainConfig().IsMetropolis(evm.BlockNumber): + cfg.JumpTable = metropolisInstructionSet case evm.ChainConfig().IsHomestead(evm.BlockNumber): cfg.JumpTable = homesteadInstructionSet default: @@ -87,6 +90,19 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter { } func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { + if in.evm.chainRules.IsMetropolis { + if in.readonly { + // if the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. The 4th stack item + // for a call operation is the value. Transfering value from one + // account to the others means the state is modified and should also + // return with an error. + if operation.writes || + ((op == CALL || op == CALLCODE) && stack.Back(3).BitLen() > 0) { + return errWriteProtection + } + } + } return nil } @@ -97,8 +113,12 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack // considered a revert-and-consume-all-gas operation. No error specific checks // should be handled to reduce complexity and errors further down the in. func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) { + // Increment the call depth which is restricted to 1024. in.evm.depth++ defer func() { in.evm.depth-- }() + // Reset the previous call's return data. It's unimportant to preserve the old buffer + // as every returning call will return new data anyway. + in.returnData = nil // Don't bother with the execution if there's no code. if len(contract.Code) == 0 { @@ -201,6 +221,11 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret verifyIntegerPool(in.intPool) } + // checks whether the operation should revert state. + if operation.reverts { + in.evm.StateDB.RevertToSnapshot(snapshot) + } + switch { case err != nil: return nil, err @@ -209,10 +234,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret case !operation.jumps: pc++ } - // if the operation returned a value make sure that is also set - // the last return data. - if res != nil { - mem.lastReturn = ret + // if the operation clears the return data (e.g. it has returning data) + // set the last return to the result of the operation. + if operation.clearsReturndata { + in.returnData = res } } return nil, nil diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 0034eacb7d..14f604fe88 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -53,13 +53,51 @@ type operation struct { valid bool // reverts determined whether the operation reverts state reverts bool + // clearsReturndata determines whether the opertions clears the return data + clearsReturndata bool } var ( - frontierInstructionSet = NewFrontierInstructionSet() - homesteadInstructionSet = NewHomesteadInstructionSet() + frontierInstructionSet = NewFrontierInstructionSet() + homesteadInstructionSet = NewHomesteadInstructionSet() + metropolisInstructionSet = NewMetropolisInstructionSet() ) +// NewMetropolisInstructionSet returns the frontier, homestead and +// metropolis instructions. +func NewMetropolisInstructionSet() [256]operation { + // instructions that can be executed during the homestead phase. + instructionSet := NewHomesteadInstructionSet() + instructionSet[STATIC_CALL] = operation{ + execute: opStaticCall, + gasCost: gasStaticCall, + validateStack: makeStackFunc(6, 1), + memorySize: memoryStaticCall, + valid: true, + } + instructionSet[REVERT] = operation{ + execute: opRevert, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 0), + valid: true, + reverts: true, + } + instructionSet[RETURNDATASIZE] = operation{ + execute: opReturnDataSize, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + } + instructionSet[RETURNDATACOPY] = operation{ + execute: opReturnDataCopy, + gasCost: gasReturnDataCopy, + validateStack: makeStackFunc(3, 0), + memorySize: memoryReturnDataCopy, + valid: true, + } + return instructionSet +} + // NewHomesteadInstructionSet returns the frontier and homestead // instructions that can be executed during the homestead phase. func NewHomesteadInstructionSet() [256]operation { @@ -810,6 +848,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(2, 0), memorySize: memoryLog, valid: true, + writes: true, }, LOG1: { execute: makeLog(1), @@ -817,6 +856,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(3, 0), memorySize: memoryLog, valid: true, + writes: true, }, LOG2: { execute: makeLog(2), @@ -824,6 +864,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(4, 0), memorySize: memoryLog, valid: true, + writes: true, }, LOG3: { execute: makeLog(3), @@ -831,6 +872,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(5, 0), memorySize: memoryLog, valid: true, + writes: true, }, LOG4: { execute: makeLog(4), @@ -838,28 +880,41 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(6, 0), memorySize: memoryLog, valid: true, - }, - CREATE: { - execute: opCreate, - gasCost: gasCreate, - validateStack: makeStackFunc(3, 1), - memorySize: memoryCreate, - valid: true, writes: true, }, + CREATE: { + execute: opCreate, + gasCost: gasCreate, + validateStack: makeStackFunc(3, 1), + memorySize: memoryCreate, + valid: true, + writes: true, + clearsReturndata: true, + }, + CREATE2: { + execute: opCreate2, + gasCost: gasCreate, + validateStack: makeStackFunc(4, 1), + memorySize: memoryCreate2, + valid: true, + writes: true, + clearsReturndata: true, + }, CALL: { - execute: opCall, - gasCost: gasCall, - validateStack: makeStackFunc(7, 1), - memorySize: memoryCall, - valid: true, + execute: opCall, + gasCost: gasCall, + validateStack: makeStackFunc(7, 1), + memorySize: memoryCall, + valid: true, + clearsReturndata: true, }, CALLCODE: { - execute: opCallCode, - gasCost: gasCallCode, - validateStack: makeStackFunc(7, 1), - memorySize: memoryCall, - valid: true, + execute: opCallCode, + gasCost: gasCallCode, + validateStack: makeStackFunc(7, 1), + memorySize: memoryCall, + valid: true, + clearsReturndata: true, }, RETURN: { execute: opReturn, diff --git a/core/vm/memory.go b/core/vm/memory.go index 6dbee94eff..99a84d2271 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -22,7 +22,6 @@ import "fmt" type Memory struct { store []byte lastGasCost uint64 - lastReturn []byte } func NewMemory() *Memory { diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 654137c70b..01e43fbc00 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -30,6 +30,10 @@ func memoryCalldataCopy(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(2)) } +func memoryReturnDataCopy(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), stack.Back(2)) +} + func memoryCodeCopy(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(2)) } @@ -54,6 +58,10 @@ func memoryCreate(stack *Stack) *big.Int { return calcMemSize(stack.Back(1), stack.Back(2)) } +func memoryCreate2(stack *Stack) *big.Int { + return calcMemSize(stack.Back(2), stack.Back(3)) +} + func memoryCall(stack *Stack) *big.Int { x := calcMemSize(stack.Back(5), stack.Back(6)) y := calcMemSize(stack.Back(3), stack.Back(4)) @@ -74,6 +82,13 @@ func memoryDelegateCall(stack *Stack) *big.Int { return math.BigMax(x, y) } +func memoryStaticCall(stack *Stack) *big.Int { + x := calcMemSize(stack.Back(4), stack.Back(5)) + y := calcMemSize(stack.Back(2), stack.Back(3)) + + return math.BigMax(x, y) +} + func memoryReturn(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(1)) } diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index d4ba7f1563..49789a22dd 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -194,6 +194,11 @@ const ( SWAP ) +const ( + RETURNDATASIZE OpCode = 0xd0 + iota + RETURNDATACOPY +) + const ( // 0xf0 range - closures CREATE OpCode = 0xf0 + iota @@ -201,7 +206,11 @@ const ( CALLCODE RETURN DELEGATECALL + STATIC_CALL + CREATE2 OpCode = 0xfb + + REVERT = 0xfd SELFDESTRUCT = 0xff ) @@ -349,13 +358,17 @@ var opCodeToString = map[OpCode]string{ LOG3: "LOG3", LOG4: "LOG4", + RETURNDATASIZE: "RETURNDATASIZE", + RETURNDATACOPY: "RETURNDATACOPY", // 0xf0 range CREATE: "CREATE", CALL: "CALL", RETURN: "RETURN", + REVERT: "REVERT", CALLCODE: "CALLCODE", DELEGATECALL: "DELEGATECALL", SELFDESTRUCT: "SELFDESTRUCT", + STATIC_CALL: "STATIC_CALL", PUSH: "PUSH", DUP: "DUP", @@ -372,136 +385,140 @@ func (o OpCode) String() string { } var stringToOp = map[string]OpCode{ - "STOP": STOP, - "ADD": ADD, - "MUL": MUL, - "SUB": SUB, - "DIV": DIV, - "SDIV": SDIV, - "MOD": MOD, - "SMOD": SMOD, - "EXP": EXP, - "NOT": NOT, - "LT": LT, - "GT": GT, - "SLT": SLT, - "SGT": SGT, - "EQ": EQ, - "ISZERO": ISZERO, - "SIGNEXTEND": SIGNEXTEND, - "AND": AND, - "OR": OR, - "XOR": XOR, - "BYTE": BYTE, - "ADDMOD": ADDMOD, - "MULMOD": MULMOD, - "SHA3": SHA3, - "ADDRESS": ADDRESS, - "BALANCE": BALANCE, - "ORIGIN": ORIGIN, - "CALLER": CALLER, - "CALLVALUE": CALLVALUE, - "CALLDATALOAD": CALLDATALOAD, - "CALLDATASIZE": CALLDATASIZE, - "CALLDATACOPY": CALLDATACOPY, - "DELEGATECALL": DELEGATECALL, - "CODESIZE": CODESIZE, - "CODECOPY": CODECOPY, - "GASPRICE": GASPRICE, - "BLOCKHASH": BLOCKHASH, - "COINBASE": COINBASE, - "TIMESTAMP": TIMESTAMP, - "NUMBER": NUMBER, - "DIFFICULTY": DIFFICULTY, - "GASLIMIT": GASLIMIT, - "EXTCODESIZE": EXTCODESIZE, - "EXTCODECOPY": EXTCODECOPY, - "POP": POP, - "MLOAD": MLOAD, - "MSTORE": MSTORE, - "MSTORE8": MSTORE8, - "SLOAD": SLOAD, - "SSTORE": SSTORE, - "JUMP": JUMP, - "JUMPI": JUMPI, - "PC": PC, - "MSIZE": MSIZE, - "GAS": GAS, - "JUMPDEST": JUMPDEST, - "PUSH1": PUSH1, - "PUSH2": PUSH2, - "PUSH3": PUSH3, - "PUSH4": PUSH4, - "PUSH5": PUSH5, - "PUSH6": PUSH6, - "PUSH7": PUSH7, - "PUSH8": PUSH8, - "PUSH9": PUSH9, - "PUSH10": PUSH10, - "PUSH11": PUSH11, - "PUSH12": PUSH12, - "PUSH13": PUSH13, - "PUSH14": PUSH14, - "PUSH15": PUSH15, - "PUSH16": PUSH16, - "PUSH17": PUSH17, - "PUSH18": PUSH18, - "PUSH19": PUSH19, - "PUSH20": PUSH20, - "PUSH21": PUSH21, - "PUSH22": PUSH22, - "PUSH23": PUSH23, - "PUSH24": PUSH24, - "PUSH25": PUSH25, - "PUSH26": PUSH26, - "PUSH27": PUSH27, - "PUSH28": PUSH28, - "PUSH29": PUSH29, - "PUSH30": PUSH30, - "PUSH31": PUSH31, - "PUSH32": PUSH32, - "DUP1": DUP1, - "DUP2": DUP2, - "DUP3": DUP3, - "DUP4": DUP4, - "DUP5": DUP5, - "DUP6": DUP6, - "DUP7": DUP7, - "DUP8": DUP8, - "DUP9": DUP9, - "DUP10": DUP10, - "DUP11": DUP11, - "DUP12": DUP12, - "DUP13": DUP13, - "DUP14": DUP14, - "DUP15": DUP15, - "DUP16": DUP16, - "SWAP1": SWAP1, - "SWAP2": SWAP2, - "SWAP3": SWAP3, - "SWAP4": SWAP4, - "SWAP5": SWAP5, - "SWAP6": SWAP6, - "SWAP7": SWAP7, - "SWAP8": SWAP8, - "SWAP9": SWAP9, - "SWAP10": SWAP10, - "SWAP11": SWAP11, - "SWAP12": SWAP12, - "SWAP13": SWAP13, - "SWAP14": SWAP14, - "SWAP15": SWAP15, - "SWAP16": SWAP16, - "LOG0": LOG0, - "LOG1": LOG1, - "LOG2": LOG2, - "LOG3": LOG3, - "LOG4": LOG4, - "CREATE": CREATE, - "CALL": CALL, - "RETURN": RETURN, - "CALLCODE": CALLCODE, - "SELFDESTRUCT": SELFDESTRUCT, + "STOP": STOP, + "ADD": ADD, + "MUL": MUL, + "SUB": SUB, + "DIV": DIV, + "SDIV": SDIV, + "MOD": MOD, + "SMOD": SMOD, + "EXP": EXP, + "NOT": NOT, + "LT": LT, + "GT": GT, + "SLT": SLT, + "SGT": SGT, + "EQ": EQ, + "ISZERO": ISZERO, + "SIGNEXTEND": SIGNEXTEND, + "AND": AND, + "OR": OR, + "XOR": XOR, + "BYTE": BYTE, + "ADDMOD": ADDMOD, + "MULMOD": MULMOD, + "SHA3": SHA3, + "ADDRESS": ADDRESS, + "BALANCE": BALANCE, + "ORIGIN": ORIGIN, + "CALLER": CALLER, + "CALLVALUE": CALLVALUE, + "CALLDATALOAD": CALLDATALOAD, + "CALLDATASIZE": CALLDATASIZE, + "CALLDATACOPY": CALLDATACOPY, + "DELEGATECALL": DELEGATECALL, + "STATIC_CALL": STATIC_CALL, + "CODESIZE": CODESIZE, + "CODECOPY": CODECOPY, + "GASPRICE": GASPRICE, + "BLOCKHASH": BLOCKHASH, + "COINBASE": COINBASE, + "TIMESTAMP": TIMESTAMP, + "NUMBER": NUMBER, + "DIFFICULTY": DIFFICULTY, + "GASLIMIT": GASLIMIT, + "EXTCODESIZE": EXTCODESIZE, + "EXTCODECOPY": EXTCODECOPY, + "POP": POP, + "MLOAD": MLOAD, + "MSTORE": MSTORE, + "MSTORE8": MSTORE8, + "SLOAD": SLOAD, + "SSTORE": SSTORE, + "JUMP": JUMP, + "JUMPI": JUMPI, + "PC": PC, + "MSIZE": MSIZE, + "GAS": GAS, + "JUMPDEST": JUMPDEST, + "PUSH1": PUSH1, + "PUSH2": PUSH2, + "PUSH3": PUSH3, + "PUSH4": PUSH4, + "PUSH5": PUSH5, + "PUSH6": PUSH6, + "PUSH7": PUSH7, + "PUSH8": PUSH8, + "PUSH9": PUSH9, + "PUSH10": PUSH10, + "PUSH11": PUSH11, + "PUSH12": PUSH12, + "PUSH13": PUSH13, + "PUSH14": PUSH14, + "PUSH15": PUSH15, + "PUSH16": PUSH16, + "PUSH17": PUSH17, + "PUSH18": PUSH18, + "PUSH19": PUSH19, + "PUSH20": PUSH20, + "PUSH21": PUSH21, + "PUSH22": PUSH22, + "PUSH23": PUSH23, + "PUSH24": PUSH24, + "PUSH25": PUSH25, + "PUSH26": PUSH26, + "PUSH27": PUSH27, + "PUSH28": PUSH28, + "PUSH29": PUSH29, + "PUSH30": PUSH30, + "PUSH31": PUSH31, + "PUSH32": PUSH32, + "DUP1": DUP1, + "DUP2": DUP2, + "DUP3": DUP3, + "DUP4": DUP4, + "DUP5": DUP5, + "DUP6": DUP6, + "DUP7": DUP7, + "DUP8": DUP8, + "DUP9": DUP9, + "DUP10": DUP10, + "DUP11": DUP11, + "DUP12": DUP12, + "DUP13": DUP13, + "DUP14": DUP14, + "DUP15": DUP15, + "DUP16": DUP16, + "SWAP1": SWAP1, + "SWAP2": SWAP2, + "SWAP3": SWAP3, + "SWAP4": SWAP4, + "SWAP5": SWAP5, + "SWAP6": SWAP6, + "SWAP7": SWAP7, + "SWAP8": SWAP8, + "SWAP9": SWAP9, + "SWAP10": SWAP10, + "SWAP11": SWAP11, + "SWAP12": SWAP12, + "SWAP13": SWAP13, + "SWAP14": SWAP14, + "SWAP15": SWAP15, + "SWAP16": SWAP16, + "LOG0": LOG0, + "LOG1": LOG1, + "LOG2": LOG2, + "LOG3": LOG3, + "LOG4": LOG4, + "CREATE": CREATE, + "CALL": CALL, + "RETURN": RETURN, + "REVERT": REVERT, + "CALLCODE": CALLCODE, + "SELFDESTRUCT": SELFDESTRUCT, + "RETURNDATASIZE": RETURNDATASIZE, + "RETURNDATACOPY": RETURNDATACOPY, } func StringToOp(str string) OpCode { diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 45bb873225..02df03fff4 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -203,8 +203,6 @@ func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (* if err == nil { if r == nil { return nil, ethereum.NotFound - } else if len(r.PostState) == 0 { - return nil, fmt.Errorf("server returned receipt without post state") } } return r, err